package com.xbongbong.paas.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.xbongbong.i18n.util.I18nMessageUtil;
import com.xbongbong.paas.constant.MessageConstant;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.sys.help.PackageHelp;
import com.xbongbong.paas.log.MongoLogHelp;
import com.xbongbong.paas.log.constant.LogMemoConstant;
import com.xbongbong.paas.pojo.IdNamePojo;
import com.xbongbong.paas.pojo.KeyValuePojo;
import com.xbongbong.paas.service.CompanyConfigService;
import com.xbongbong.paas.service.PerformanceService;
import com.xbongbong.paas.service.PerformanceSetService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.helper.PageHelper;
import com.xbongbong.paas.toolbox.util.Arith;
import com.xbongbong.paas.toolbox.util.BeanUtil;
import com.xbongbong.paas.toolbox.util.CloneUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.util.PageHelperUtil;
import com.xbongbong.paas.toolbox.util.StringUtil;
import com.xbongbong.paas.toolbox.wrap.BaseDTO;
import com.xbongbong.pro.companyconfig.pojo.dto.CompanyConfigGetWorkingDayMonthDTO;
import com.xbongbong.pro.companyconfig.pojo.dto.CompanyConfigGetWorkingDayWeekDTO;
import com.xbongbong.pro.companyconfig.pojo.dto.CompanyConfigHasBeenEnableDTO;
import com.xbongbong.pro.companyconfig.pojo.vo.CompanyConfigGetWorkingDayMonthVO;
import com.xbongbong.pro.companyconfig.pojo.vo.CompanyConfigGetWorkingDayWeekVO;
import com.xbongbong.pro.companyconfig.pojo.vo.CompanyConfigHasBeenEnableVO;
import com.xbongbong.pro.constant.CommonConstant;
import com.xbongbong.pro.constant.I18nStringConstant;
import com.xbongbong.pro.constant.RegExConstant;
import com.xbongbong.pro.domain.entity.ChartEntity;
import com.xbongbong.pro.enums.PackageTypeEnum;
import com.xbongbong.pro.enums.TimeTypeEnum;
import com.xbongbong.pro.enums.errorcodes.PerformanceErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.pro.enums.menu.enums.OtherSetEnum;
import com.xbongbong.pro.enums.permission.enums.ProPermissionAliasEnum;
import com.xbongbong.pro.performance.pojo.PerformancePojo;
import com.xbongbong.pro.performance.pojo.dto.PerformanceAggDepartmentDTO;
import com.xbongbong.pro.performance.pojo.dto.PerformanceChartListDTO;
import com.xbongbong.pro.performance.pojo.dto.PerformanceConfigListDTO;
import com.xbongbong.pro.performance.pojo.dto.PerformanceDetailDTO;
import com.xbongbong.pro.performance.pojo.dto.PerformanceEditListDTO;
import com.xbongbong.pro.performance.pojo.dto.PerformanceItemDTO;
import com.xbongbong.pro.performance.pojo.dto.PerformanceListDTO;
import com.xbongbong.pro.performance.pojo.dto.PerformanceSaveAppDTO;
import com.xbongbong.pro.performance.pojo.dto.PerformanceSaveWebDTO;
import com.xbongbong.pro.performance.pojo.dto.PerformanceSumDataDTO;
import com.xbongbong.pro.performance.pojo.vo.PerformanceAggDepartmentVO;
import com.xbongbong.pro.performance.pojo.vo.PerformanceChartListVO;
import com.xbongbong.pro.performance.pojo.vo.PerformanceConfigListVO;
import com.xbongbong.pro.performance.pojo.vo.PerformanceDetailVO;
import com.xbongbong.pro.performance.pojo.vo.PerformanceEditListVO;
import com.xbongbong.pro.performance.pojo.vo.PerformanceItemVO;
import com.xbongbong.pro.performance.pojo.vo.PerformanceListVO;
import com.xbongbong.pro.performance.pojo.vo.PerformanceSaveVO;
import com.xbongbong.pro.performance.pojo.vo.PerformanceSumDataVO;
import com.xbongbong.pro.performanceset.pojo.PerformanceChartListPojo;
import com.xbongbong.pro.performanceset.pojo.PerformanceSetExplainPojo;
import com.xbongbong.pro.service.toolbox.statistic.help.FiscalYearHelp;
import com.xbongbong.pro.service.toolbox.statistic.help.PerformanceHelp;
import com.xbongbong.pro.statistic.enums.ChartTypeEnum;
import com.xbongbong.pro.statistic.enums.StatisticsTypeEnum;
import com.xbongbong.pro.statistic.model.ChartCustomModel;
import com.xbongbong.pro.statistic.model.ChartModel;
import com.xbongbong.pro.statistic.pojo.FiscalYearTimePojo;
import com.xbongbong.saas.constant.BasicConstant;
import com.xbongbong.saas.constant.PageConstant;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.domain.entity.PerformanceEntity;
import com.xbongbong.saas.enums.AssessTypeEnum;
import com.xbongbong.saas.enums.CompanyConfigEnum;
import com.xbongbong.saas.enums.MinCycleEnum;
import com.xbongbong.saas.enums.OperateModuleTypeEnum;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.PerformanceOperatorEnum;
import com.xbongbong.saas.enums.PerformanceTitleEnum;
import com.xbongbong.saas.enums.TabTypeEnum;
import com.xbongbong.saas.model.PerformanceModel;
import com.xbongbong.saas.toolbox.help.BasicHelper;
import com.xbongbong.sys.domain.entity.DepartmentEntity;
import com.xbongbong.sys.domain.entity.UserEntity;
import com.xbongbong.sys.enums.CompanyStructTypeEnum;
import com.xbongbong.sys.enums.DataPermissionEnum;
import com.xbongbong.sys.model.CompanyConfigModel;
import com.xbongbong.sys.model.DepartmentModel;
import com.xbongbong.sys.model.UserModel;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * @description: 业绩目标service
 * @Author: hongxiao
 * @date: 2019-01-22 15:16
 */
@Service("performanceService")
public class PerformanceServiceImpl implements PerformanceService {

    private static final Logger LOG = LoggerFactory.getLogger(PerformanceServiceImpl.class);

    @Resource
    private CompanyConfigModel companyConfigModel;
    @Resource
    private UserModel userModel;
    @Resource
    private ChartModel chartModel;
    @Resource
    private PerformanceModel performanceModel;
    @Resource
    private DepartmentModel departmentModel;
    @Resource
    private CompanyConfigService companyConfigService;
    @Resource
    private PerformanceSetService performanceSetService;
    @Resource
    private PerformanceHelp performanceHelp;
    @Resource
    private MongoLogHelp mongoLogHelp;
    @Resource
    private PackageHelp packageHelp;
    @Resource
    private ChartCustomModel chartCustomModel;


    /**
     * web端-获取业绩目标配置
     *
     * @param performanceConfigListDTO 入参
     * @return
     * @author hongxiao
     * @addTime: 2019-01-25 09:57
     * @modified by:
     * @updateTime: 2019-01-25 09:57
     * @version
     * @since
     */
    @Override
    public PerformanceConfigListVO configList(PerformanceConfigListDTO performanceConfigListDTO) throws XbbException {
        PerformanceConfigListVO configListVO = new PerformanceConfigListVO();

        String corpid = performanceConfigListDTO.getCorpid();

        Integer now = DateUtil.getInt();
        // 当前自然月
        int month = DateUtil.getMonth4Someday(now);
        // 当前自然年
        int year = DateUtil.getYear4Someday(now);

        // 财年
        int startMonth = companyConfigModel.getFiscalStartMonth(corpid);
        boolean isFiscalYear = startMonth != 1;
        String lableFiscalYear = FiscalYearHelp.getLableFiscalYear(startMonth, null);

        // 当前月份所在的财年
        int fiscalYear = DateUtil.getFiscalYearByMonth(year, month, startMonth);

        // 一键汇总按钮
        boolean aggDepartment = false;
        // 菜单权限,需要的权限为（performanceSet,paramSet,import）
        List<String> permissionList = new ArrayList<>();
        Set<String> saasPermissions = performanceConfigListDTO.getLoginUser().getPermSet();
        Integer feeType = packageHelp.getFeeType(corpid);
        if(saasPermissions.contains(ProPermissionAliasEnum.PERFORMANCE_OBJECT_SET.getAlias()) && saasPermissions.contains(ProPermissionAliasEnum.OBJECTIVE_IMPORT.getAlias())) {
            permissionList.add(PerformanceOperatorEnum.IMPORT.getKey());
        }
        if(saasPermissions.contains(ProPermissionAliasEnum.PERFORMANCE_OBJECT_SET.getAlias()) && saasPermissions.contains(ProPermissionAliasEnum.PERFORMANCE_SET.getAlias())) {
            permissionList.add(PerformanceOperatorEnum.PARAM_SET.getKey());
            if(Objects.equals(feeType, PackageTypeEnum.ULTIMATE.getType())) {
                permissionList.add(PerformanceOperatorEnum.PERFORMANCE_SET.getKey());
            }
        }

        // 目标页签
        JSONArray tabList = TabTypeEnum.getByFeeType(feeType);

        configListVO.setStartMonth(startMonth);
        configListVO.setFiscalYear(fiscalYear);
        configListVO.setIsFiscalYear(isFiscalYear);
        configListVO.setLableFiscalYear(lableFiscalYear);
        configListVO.setAggDepartment(aggDepartment);
        configListVO.setPermissionList(permissionList);
        configListVO.setTabList(tabList);

        return configListVO;
    }

    /**
     * @param performanceConfigListDTO 入参
     * @return
     * @author hongxiao
     * @addTime: 2019-01-25 09:58
     * @modified by:
     * @updateTime: 2019-01-25 09:58
     * @version
     * @since
     */
    @Override
    public PerformanceConfigListVO configListForMobile(PerformanceConfigListDTO performanceConfigListDTO) throws XbbException {
        PerformanceConfigListVO configListVO = new PerformanceConfigListVO();

        String corpid = performanceConfigListDTO.getCorpid();
        String userId = performanceConfigListDTO.getUserId();
        UserEntity userEntity = userModel.getByKey(userId, corpid);
        if (userEntity == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100004, SystemErrorCodeEnum.API_ERROR_100004.getMsg());
        }

        // 财年
        int startMonth = companyConfigModel.getFiscalStartMonth(corpid);
        boolean isFiscalYear = startMonth != 1;
        // 判断当前月处于哪个财年
        Integer now = DateUtil.getInt();
        // 当前自然月
        int month = DateUtil.getMonth4Someday(now);
        // 当前自然年
        int year = DateUtil.getYear4Someday(now);
        // 当前月份所在的财年
        int fiscalYear = DateUtil.getFiscalYearByMonth(year, month, startMonth);

        List<String> permissionList = new ArrayList<>();
        Boolean appSet = canSetPerformanceInMobile(userEntity);
        if (appSet) {
            permissionList.add(PerformanceOperatorEnum.APP_SET.getKey());
        }
        Integer feeType = packageHelp.getFeeType(corpid);
        // 目标页签
        JSONArray tabList = TabTypeEnum.getByFeeType(feeType);

        configListVO.setStartMonth(startMonth);
        configListVO.setFiscalYear(fiscalYear);
        configListVO.setIsFiscalYear(isFiscalYear);
        configListVO.setPermissionList(permissionList);
        configListVO.setTabList(tabList);

        return configListVO;
    }


    @Override
    public PerformanceItemVO item(PerformanceItemDTO performanceItemDTO) throws XbbException {
        PerformanceItemVO itemVO = new PerformanceItemVO();

        String corpid = performanceItemDTO.getCorpid();
        String userId = performanceItemDTO.getUserId();
        Long id = performanceItemDTO.getSetId();
        Integer statisticsType = performanceItemDTO.getStatisticsType();
        UserEntity userEntity = userModel.getByKey(userId, corpid);
        if (userEntity == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100004, SystemErrorCodeEnum.API_ERROR_100004.getMsg());
        }
        String platform = performanceItemDTO.getPlatform();
        // 获取目标实体
        ChartEntity setEntity = performanceHelp.getSetEntity(statisticsType,corpid,id);

        // 移动端判断是否有设置权限
        if (StringConstant.PLATFORM_DINGTALK.equals(platform) && !canSetPerformanceInMobile(userEntity)) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240019, PerformanceErrorCodeEnum.API_ERROR_240019.getMsg());
        }

        // 考核方式：1动态数值型,2固定数值型
        PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(setEntity);
        Integer assessType = explainPojo.getAssessType();
        JSONObject jsonObject = new JSONObject();
        if (AssessTypeEnum.FIXED.getCode() == assessType) {
            // 固定数值型
            jsonObject.putAll(fixedData(corpid, setEntity, explainPojo));
        } else {

            Integer year = performanceItemDTO.getYear();
            Integer minCycle = explainPojo.getMinCycle();
            MinCycleEnum minCycleEnum = MinCycleEnum.getByCode(minCycle);
            if (minCycleEnum == null) {
                throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240022);
            }
            // 当最小考核周期是周时，在获取目标时，把自然年转换成财年
            if (MinCycleEnum.WEEK == minCycleEnum) {
                // 需要通过year和month，获取财年年份
                Integer month = performanceItemDTO.getMonth();
                if (month == null) {
                    throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006,PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.MONTH));
                }
                Integer fiscalYear = DateUtil.getFiscalYearByMonth(year, month, companyConfigModel.getFiscalStartMonth(corpid));
                performanceItemDTO.setYear(fiscalYear);
            }

            // 转化前端传参为pojo
            PerformancePojo performancePojo = new PerformancePojo();
            BeanUtil.copyProperties(performanceItemDTO, performancePojo);
            // 部门或员工id
            CompanyStructTypeEnum companyStructTypeEnum = CompanyStructTypeEnum.getByCode(performanceItemDTO.getCompanyStructType());
            if(companyStructTypeEnum == CompanyStructTypeEnum.UNKNOWN) {
                throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240023);
            }
            // 可以不传
            if (CompanyStructTypeEnum.USER == companyStructTypeEnum) {
                performancePojo.setUserId(performanceItemDTO.getCheckedUserId());
            } else {
                Long checkedDepId;
                try {
                    checkedDepId = Long.parseLong(performanceItemDTO.getCheckedDepId());
                } catch (NumberFormatException e) {
                    checkedDepId = null;
                }
                performancePojo.setDepartmentId(checkedDepId);
            }

            // 获取到目标对象
            PerformanceEntity performanceEntity = performanceModel.getPerformanceEntity(setEntity.getCorpid(), performancePojo);
            // 动态数值型
            // 在包装目标时，放入自然年
            performancePojo.setYear(year);
            jsonObject.putAll(changeData(corpid, setEntity, minCycle, performancePojo, performanceEntity, "item"));

            // 当最小考核周期为月的时候，只读出封装的月份相关信息即可（剔除年、半年、季度等不必要信息）
            if (StringConstant.PLATFORM_DINGTALK.equals(performanceItemDTO.getPlatform()) && MinCycleEnum.MONTH == minCycleEnum) {
                JSONArray month = jsonObject.getJSONObject("data").getJSONArray("month");
                // 转存data时使用
                JSONObject data = new JSONObject();
                data.put("month", month);
                jsonObject.put("data", data);
            }
        }

        itemVO.setItem(jsonObject);
        return itemVO;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public PerformanceSaveVO saveWeb(PerformanceSaveWebDTO performanceSaveWebDTO) throws XbbException {
        PerformanceSaveVO saveWebVO = new PerformanceSaveVO();

        String corpid = performanceSaveWebDTO.getCorpid();
        Long setId = performanceSaveWebDTO.getSetId();
        Integer companyStructType = performanceSaveWebDTO.getCompanyStructType();

        // 获取目标实体
        ChartEntity setEntity = performanceHelp.getSetEntity(performanceSaveWebDTO.getStatisticsType(),corpid,setId);

        // 考核方式：1动态数值型,2固定数值型
        PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(setEntity);
        Integer assessType = explainPojo.getAssessType();

        // 考核方式：1动态数值型,2固定数值型
        if (assessType == AssessTypeEnum.FIXED.getCode()) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240010, PerformanceErrorCodeEnum.API_ERROR_240010.getMsg());
        }
        // 业绩类型：1员工的业绩 2部门的业绩
        CompanyStructTypeEnum companyStructTypeEnum = CompanyStructTypeEnum.getByCode(companyStructType);
        if (companyStructTypeEnum == CompanyStructTypeEnum.UNKNOWN) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240023);
        }
        List<String> userIdIn = performanceSaveWebDTO.getUserIdIn();
        List<Long> depIdIn = performanceSaveWebDTO.getDepIdIn();
        boolean userFlag = companyStructTypeEnum == CompanyStructTypeEnum.USER && (userIdIn == null || userIdIn.size() == 0);
        boolean depFlag = companyStructTypeEnum == CompanyStructTypeEnum.DEPARTMENT && (depIdIn == null || depIdIn.size() == 0);
        if (userFlag || depFlag) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.ASSESSMENT_OBJECT));
        }
        // 处理目标值
        JSONObject targetObject = performanceSaveWebDTO.getTarget();
        checkTarget(targetObject);

        Integer minCycle = explainPojo.getMinCycle();
        // 最小考核周期为周，需要传月份
        Integer month = performanceSaveWebDTO.getMonth();
        if (MinCycleEnum.WEEK.getCode() == minCycle && month == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.MONTH));
        }

        // 日志内部方法实现
        saveTarget(performanceSaveWebDTO, minCycle, setEntity.getName());

        return saveWebVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PerformanceEditListVO editList(PerformanceEditListDTO performanceEditListDTO) throws XbbException {
        PerformanceEditListVO editListVO = new PerformanceEditListVO();

        String corpid = performanceEditListDTO.getCorpid();
        Long id = performanceEditListDTO.getId();
        JSONObject valueObject = performanceEditListDTO.getValue();
        if (id == null || id == 0) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240013, PerformanceErrorCodeEnum.API_ERROR_240013.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.TARGET));
        }
        PerformanceEntity performanceEntity = performanceModel.getByKey(id, corpid);
        if (performanceEntity == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240013, String.format(PerformanceErrorCodeEnum.API_ERROR_240013.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.TARGET)));
        }
        // 克隆旧对象用来生成更新日志

        /*
         * 处理目标值，此处格式为{"key": "m1", "value": 1200}，或者{"key": "w12", "value": 22}
         */
        // 值为：year、m1/m2...、w1/w2...
        String key = valueObject.getString("key");
        Double value = valueObject.getDouble("value");
        if (value == null || value == -1) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240004, PerformanceErrorCodeEnum.API_ERROR_240004.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.PERFORMANCE_TARGET));
        }
        // 值为：year、month、week
        String alias = performanceEditListDTO.getAlias();
        if (StringUtil.isEmpty(alias) || StringUtil.isEmpty(key)) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.UPDATE_TARGET));
        }
        JSONObject oldTargetObject = performanceEntity.getTarget();
        String memo = "";
        if (TimeTypeEnum.YEAR.getAlias().equals(alias)) {
            memo = I18nMessageUtil.getMessage(I18nStringConstant.YEAR_TARGET_REVISED) + value;
            oldTargetObject.put(alias, value);
        } else if (TimeTypeEnum.MONTH.getAlias().equals(alias) || TimeTypeEnum.WEEK.getAlias().equals(alias)) {
            if (TimeTypeEnum.MONTH.getAlias().equals(alias)) {
                // 月索引
                Integer index = StringUtil.toInt(key.replaceAll("m", ""), 0);
                if (!key.contains("m") || index <= 0 || index > BasicConstant.MAX_MONTH) {
                    throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240024);
                }
                memo = I18nMessageUtil.getMessage(I18nStringConstant.MONTH_TARGET_REVISED) + value;
            } else {
                // 周索引
                Integer index = StringUtil.toInt(key.replaceAll("w", ""), 0);
                if (!key.contains("w") || index <= 0) {
                    throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240024);
                }
                memo = I18nMessageUtil.getMessage(I18nStringConstant.WEEK_TARGET_REVISED) + value;
            }
            // 旧的月度/周目标
            JSONObject oldPerObject = oldTargetObject.getJSONObject(alias);
            if (oldPerObject == null) {
                oldPerObject = new JSONObject();
            }
            // 把新设置的[单个]月/周的目标置入
            oldPerObject.put(key, value);
            // 把月/周目标置入目标值内
            oldTargetObject.put(alias, oldPerObject);
        } else {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.UPDATE_TARGET));
        }
        performanceEntity.setTarget(oldTargetObject);
        performanceEntity.setUpdateTime((long) DateUtil.getInt());
        try {
            performanceModel.update(performanceEntity);
        } catch (Exception e) {
            LOG.error("更新业绩目标失败", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
        }


        // 日志
        String opUserName = performanceEditListDTO.getLoginUserName();
        //备注
        String opMemo = opUserName + I18nMessageUtil.getMessage(I18nStringConstant.EDITED_GOAL) + memo;
        //日志
        mongoLogHelp.buildLog(corpid, performanceEditListDTO.getUserId(), opUserName, OperateModuleTypeEnum.PerformanceObject, OperateTypeEnum.EDIT, "", OtherSetEnum.GOAL_MANAGEMENT.getName(), opMemo, performanceEditListDTO.getHttpHeader());
        return editListVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PerformanceSaveVO saveApp(PerformanceSaveAppDTO performanceSaveAppDTO) throws XbbException {
        PerformanceSaveVO saveVO = new PerformanceSaveVO();

        String corpid = performanceSaveAppDTO.getCorpid();
        String userId = performanceSaveAppDTO.getUserId();
        UserEntity userEntity = userModel.getByKey(userId, corpid);
        if (userEntity == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100004, SystemErrorCodeEnum.API_ERROR_100004.getMsg());
        }
        // 获取目标实体
        ChartEntity setEntity = performanceHelp.getSetEntity(performanceSaveAppDTO.getStatisticsType(),corpid,performanceSaveAppDTO.getSetId());

        // 移动端判断是否有设置权限
        String platform = performanceSaveAppDTO.getPlatform();
        if (StringConstant.PLATFORM_DINGTALK.equals(platform) && !canSetPerformanceInMobile(userEntity)) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240019, PerformanceErrorCodeEnum.API_ERROR_240019.getMsg());
        }
        // 考核方式：1动态数值型,2固定数值型
        PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(setEntity);
        Integer assessType = explainPojo.getAssessType();

        // 考核方式：1动态数值型,2固定数值型
        if (assessType == AssessTypeEnum.FIXED.getCode()) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240010, PerformanceErrorCodeEnum.API_ERROR_240010.getMsg());
        }

        PerformanceSaveWebDTO performanceSaveDTO = new PerformanceSaveWebDTO();
        BeanUtil.copyProperties(performanceSaveAppDTO, performanceSaveDTO);
        // 判断业绩类型是否为空
        CompanyStructTypeEnum companyStructTypeEnum = CompanyStructTypeEnum.getByCode( performanceSaveAppDTO.getCompanyStructType());
        if (companyStructTypeEnum == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240025);
        }


        // 将员工或者部门分类放入paramJSON中
        if (CompanyStructTypeEnum.USER == companyStructTypeEnum) {
            String checkedUserId = performanceSaveAppDTO.getCheckedUserId();
            if(StringUtil.isEmpty(checkedUserId)) {
                throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240026);
            }
            List<String> userIdIn = new ArrayList<>();
            userIdIn.add(checkedUserId);
            performanceSaveDTO.setUserIdIn(userIdIn);
        } else if (CompanyStructTypeEnum.DEPARTMENT == companyStructTypeEnum) {
            String checkedDepIdStr = performanceSaveAppDTO.getCheckedDepId();
            if(checkedDepIdStr == null || Objects.equals(BasicConstant.ZERO.toString(), checkedDepIdStr)) {
                throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240027);
            }

            Long checkedDepId;
            try {
                checkedDepId = Long.parseLong(checkedDepIdStr);
            } catch (NumberFormatException e) {
                checkedDepId = null;
            }
            if (Objects.isNull(checkedDepId)) {
                throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240027);
            }
            List<Long> depIdIn = new ArrayList<>();
            depIdIn.add(checkedDepId);
            performanceSaveDTO.setDepIdIn(depIdIn);
        } else {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240023);
        }
        Integer year = performanceSaveDTO.getYear();
        if (year == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.YEAR));
        }
        // 处理目标值
        JSONObject targetObject = performanceSaveDTO.getTarget();
        if (targetObject == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240004, PerformanceErrorCodeEnum.API_ERROR_240004.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.PERFORMANCE_TARGET));
        }
        Integer minCycle = explainPojo.getMinCycle();
        // 最小考核周期为周，需要传月份
        // 在存储周目标时，需要进行处理，将周目标处理生成月目标
        if (MinCycleEnum.WEEK.getCode() == minCycle) {
            Integer month = performanceSaveAppDTO.getMonth();
            if (month == null) {
                throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.MONTH));
            }
            // 获取目标值中的周目标值
            JSONObject weekObject = targetObject.getJSONObject("week");
            if (weekObject == null) {
                throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240004, PerformanceErrorCodeEnum.API_ERROR_240004.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.WEEK_TARGET));
            }
            // 将周目标值汇总成月目标值
            Set<String> weeks = weekObject.keySet();
            Double monthTarget = 0D;
            for (String weekKey : weeks) {
                Double weekTarget = weekObject.getDouble(weekKey);
                if (null != weekTarget && weekTarget >= 0) {
                    monthTarget += weekTarget;
                }
            }
            // 确定自然月份对应的财年月份
            Integer startMonth = companyConfigModel.getFiscalStartMonth(corpid);
            Integer fiscalMonth = DateUtil.getFiscalMonth(startMonth, month);
            String key = "m" + fiscalMonth;
            // 将月目标包装好放入target中
            JSONObject monthObject = new JSONObject();
            monthObject.put(key, monthTarget);
            targetObject.put("month", monthObject);
        }
        performanceSaveDTO.setTarget(targetObject);
        // 发起保存指标方法，日志内部方法实现
        saveTarget(performanceSaveDTO, minCycle, setEntity.getName());

        return saveVO;
    }

    @Override
    public PerformanceListVO list(PerformanceListDTO performanceListDTO) throws XbbException {
        PerformanceListVO listVO = new PerformanceListVO();

        String corpid = performanceListDTO.getCorpid();
        String userId = performanceListDTO.getUserId();
        UserEntity userEntity = userModel.getByKey(userId, corpid);
        if (userEntity == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100004, SystemErrorCodeEnum.API_ERROR_100004.getMsg());
        }
        // 获取目标实体
        ChartEntity setEntity = performanceHelp.getSetEntity(performanceListDTO.getStatisticsType(),corpid,performanceListDTO.getSetId());

        // 考核方式：1动态数值型,2固定数值型
        PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(setEntity);
        Integer assessType = explainPojo.getAssessType();

        JSONObject jsonObject = new JSONObject();
        // 考核方式：1动态数值型,2固定数值型
        if (assessType == AssessTypeEnum.FIXED.getCode()) {
            // 固定数值型
            jsonObject.putAll(fixedData(corpid, setEntity, explainPojo));
        } else {
            // 动态数值型
            jsonObject.putAll(dynamicList(userEntity, setEntity, explainPojo.getMinCycle(), performanceListDTO));
        }

        listVO.setItem(jsonObject);
        return listVO;
    }

    @Override
    public PerformanceSumDataVO sumData(PerformanceSumDataDTO performanceSumDataDTO) throws XbbException {
        PerformanceSumDataVO sumDataVO = new PerformanceSumDataVO();

        String corpid = performanceSumDataDTO.getCorpid();
        String userId = performanceSumDataDTO.getUserId();
        Integer statisticsType = performanceSumDataDTO.getStatisticsType();
        Long setId = performanceSumDataDTO.getSetId();
        Integer year = performanceSumDataDTO.getYear();
        UserEntity userEntity = userModel.getByKey(userId, corpid);
        if (userEntity == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100004, SystemErrorCodeEnum.API_ERROR_100004.getMsg());
        }

        // 获取目标实体
        ChartEntity setEntity = performanceHelp.getSetEntity(performanceSumDataDTO.getStatisticsType(),corpid,performanceSumDataDTO.getSetId());


        // 业绩类型：1员工的业绩 2部门的业绩
        Integer companyStructType = performanceSumDataDTO.getCompanyStructType();
        CompanyStructTypeEnum companyStructTypeEnum = CompanyStructTypeEnum.getByCode(companyStructType);
        if (companyStructTypeEnum == CompanyStructTypeEnum.UNKNOWN) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240023);
        }
        List<KeyValuePojo> sumData = new ArrayList<>();
        if (companyStructTypeEnum == CompanyStructTypeEnum.DEPARTMENT) {
            sumDataVO.setList(sumData);
            return sumDataVO;
        }

        // 考核方式：1动态数值型,2固定数值型
        PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(setEntity);
        Integer assessType = explainPojo.getAssessType();

        if (assessType == AssessTypeEnum.FIXED.getCode()) {
            // 考核方式为固定数值的，无需汇总
            sumDataVO.setList(sumData);
            return sumDataVO;
        }
        // 财年起始月份
        int startMonth = companyConfigModel.getFiscalStartMonth(corpid);
        Integer month = performanceSumDataDTO.getMonth();
        Integer fiscalYear = year;
        // 筛选的员工userId
        String checkedUserId = performanceSumDataDTO.getCheckedUserId();
        /*
         * 需要注意--对于year参数，根据最小考核周期的不同，则代表不同的含义：
         * （1）最小考核周期为“月”，则year代表财年。例如，传入2018，则代表是2018财年，实际当前时间可能才在2017年
         * （2）最小考核周期为“周”，则year代表自然年，结合“month”参数，如果year=2018，month=7，就是代表的18年7月
         * 另外，tb_performance表内的year是财年
         */
        //最小考核周期
        Integer minCycle = explainPojo.getMinCycle();
        MinCycleEnum minCycleEnum = MinCycleEnum.getByCode(minCycle);
        if (minCycleEnum == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240022);
        }
        Map<String, Object> param = new HashMap<>(16);
        param.put("corpid", corpid);
        param.put("del", DelEnum.NORMAL.getDel());
        param.put("setId", setEntity.getId());
        param.put("objectiveType", companyStructType);
        param.put("year", year);
        param.put("statisticsType",statisticsType);
        if (MinCycleEnum.WEEK == minCycleEnum) {
            // 需要通过year和month，获取财年年份
            if (month == null) {
                throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.MONTH));
            }
            // 计算出财年年份
            fiscalYear = DateUtil.getFiscalYearByMonth(year, month, startMonth);
            param.put("year", fiscalYear);
        }

        List<IdNamePojo> permissionList = performanceHelp.getPermissionList(setEntity);

        // 考核的员工id列表
        Set<String> userIdIn = performanceSetService.getPermission2UserIdsRetainSub(userEntity, setId, permissionList, null);
        //代码优化 - 不改原方案，只优化实现：如果筛选员工，则先校验是否在考核范围，然后重置userIdIn只把筛选的放入，从而减小后续filterOutDepartingUser查询的体量
        if (!StringUtil.isEmpty(checkedUserId)) {
            if (!userIdIn.contains(checkedUserId)) {
                throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240012, PerformanceErrorCodeEnum.API_ERROR_240012.getMsg(), I18nMessageUtil.getMessage(CommonConstant.EMPLOYEE));
            }
            userIdIn.clear();
            userIdIn.add(checkedUserId);
            userIdIn.add("-1");
        }
        Set<String> afterFilterUserIds = userModel.filterOutDepartingUser(userIdIn, userEntity.getCorpid());
        param.put("userIdIn", afterFilterUserIds);

        List<PerformanceEntity> list = (List<PerformanceEntity>) BasicHelper.findEntitysByImitatePage(param, performanceModel);

        // 索引--总目标，如key为“m1”、“w1”；value为“1200”
        Map<String, Double> totalTargetMap = new HashMap<>(16);
        Double totalYear = 0D;
        if (MinCycleEnum.WEEK == minCycleEnum) {
            // 周索引--区间，比如key="w1"，value="07-02至07-08"
            Map<String, String> weekPeriodMap = FiscalYearHelp.getWeekMap4Month(fiscalYear, year, month, startMonth);
            for (Map.Entry<String, String> entry : weekPeriodMap.entrySet()) {
                // 初始化
                totalTargetMap.put(entry.getKey(), 0D);
            }
            for (PerformanceEntity entity : list) {
                Double yearTarget = entity.getTargetValue4Y(TimeTypeEnum.YEAR.getAlias());
                if (yearTarget != -1) {
                    totalYear += yearTarget;
                }
                // 求和周目标
                JSONObject weekObject = entity.getPerTargetObject4MSW(TimeTypeEnum.WEEK.getAlias());
                for (Map.Entry<String, String> entry : weekPeriodMap.entrySet()) {
                    String weekKey = entry.getKey();
                    Double value = entity.getTargetValue4MSW(weekObject, weekKey);
                    Double weekTotal = totalTargetMap.get(weekKey);
                    if (value != -1) {
                        weekTotal += value;
                    }
                    totalTargetMap.put(weekKey, weekTotal);
                }
            }
        } else {
            for (int i = BasicConstant.MIN_MONTH; i <= BasicConstant.MAX_MONTH; i++) {
                // 初始化
                totalTargetMap.put("m" + i, 0D);
            }
            for (PerformanceEntity entity : list) {
                Double yearTarget = entity.getTargetValue4Y(TimeTypeEnum.YEAR.getAlias());
                if (yearTarget != -1) {
                    totalYear += yearTarget;
                }
                // 求和月目标
                JSONObject monthTarget = entity.getPerTargetObject4MSW(TimeTypeEnum.MONTH.getAlias());
                for (int i = BasicConstant.MIN_MONTH; i <= BasicConstant.MAX_MONTH; i++) {
                    String key = "m" + i;
                    Double value = entity.getTargetValue4MSW(monthTarget, key);
                    Double total = totalTargetMap.get(key);
                    if (value != -1) {
                        total += value;
                    }
                    totalTargetMap.put(key, total);
                }
            }
        }
        // 塞入年目标汇总
        KeyValuePojo keyValuePojo = new KeyValuePojo("year", StringUtil.formatDouble(totalYear));
        sumData.add(keyValuePojo);
        // 返回汇总数据：年汇总、各个月份/周汇总
        for (Map.Entry<String, Double> entry : totalTargetMap.entrySet()) {
            String valueStr = StringUtil.formatDouble(entry.getValue());
            KeyValuePojo pojo = new KeyValuePojo(entry.getKey(), valueStr);
            sumData.add(pojo);
        }

        sumDataVO.setList(sumData);
        return sumDataVO;
    }

    @Override
    public PerformanceDetailVO detail(PerformanceDetailDTO performanceDetailDTO) throws XbbException {
        PerformanceDetailVO detailVO = new PerformanceDetailVO();

        String corpid = performanceDetailDTO.getCorpid();
        String userId = performanceDetailDTO.getUserId();
        Integer statisticsType= performanceDetailDTO.getStatisticsType();
        if (!StatisticsTypeEnum.getStatisticTypes().contains(statisticsType)){
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240030,PerformanceErrorCodeEnum.API_ERROR_240030.getMsg());
        }
        UserEntity userEntity = userModel.getByKey(userId, corpid);
        if (userEntity == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100004, SystemErrorCodeEnum.API_ERROR_100004.getMsg());
        }
        HashMap<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid",corpid);
        param.put("del",DelEnum.NORMAL.getDel());
        param.put("statisticsType", statisticsType);
        param.put("page",performanceDetailDTO.getPage());
        param.put("enable",BasicConstant.ONE);
        PageHelper pageHelper;
        List<ChartEntity> list;
        try {
            if (Objects.equals(StatisticsTypeEnum.SYSTEM_STATISTIC.getCode(),statisticsType)){
                String orderByStr = "update_time desc,sort desc, id asc ";
                list = performanceHelp.getViewList(userEntity,orderByStr);
                int page = performanceDetailDTO.getPage();
                int pageSize = performanceDetailDTO.getPageSize();
                int totalSize = list.size();
                if (CollectionUtils.isNotEmpty(list)){
                    list = list.subList((page - 1) * pageSize,(page * pageSize >= list.size()) ? (list.size()) : page * pageSize);
                }
                pageHelper = PageHelperUtil.initPageHelper(totalSize,page,pageSize, PageConstant.DEFAULT_PAGE_SIZE);
            }else{
                param.put("orderByStr","update_time desc");
                param.put("chartType",ChartTypeEnum.CUSTOMER_PERFORMANCE.getCode());
                pageHelper = PageHelperUtil.getPageHelper(param, chartCustomModel, performanceDetailDTO.getPageSize());
                list = (List<ChartEntity>) PageHelperUtil.getEntityList(param, pageHelper, chartCustomModel);
            }
        } catch (Exception e) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240029,PerformanceErrorCodeEnum.API_ERROR_240029.getMsg());
        }

        Integer year = performanceDetailDTO.getYear();
        if (year == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240028);
        }

        String checkedUserId = performanceDetailDTO.getCheckedUserId();
        // 筛选的员工或部门id
        Long checkedDepId = performanceDetailDTO.getCheckedDepId();

        // 业绩类型：1员工的业绩 2部门的业绩
        Integer companyStructType = performanceDetailDTO.getCompanyStructType();
        CompanyStructTypeEnum companyStructTypeEnum = CompanyStructTypeEnum.getByCode(companyStructType);
        if (companyStructTypeEnum == CompanyStructTypeEnum.UNKNOWN) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240025);
        }


        boolean userIdFlag = companyStructTypeEnum == CompanyStructTypeEnum.USER && StringUtil.isEmpty(checkedUserId);
        boolean depIdFlag = companyStructTypeEnum == CompanyStructTypeEnum.DEPARTMENT && (checkedDepId == null || checkedDepId == 0);
        if (userIdFlag || depIdFlag) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.ASSESSMENT_OBJECT));
        }

        Set<Long> setIdIn = new HashSet<>();
        // 指标id--指标实体
        Map<Long, ChartEntity> idSetMap = new HashMap<>(16);
        // 指标id--JSONObject对象:该指标对应的目标值等信息
        Map<Long, JSONObject> idObjMap = new HashMap<>(16);
        List<ChartEntity> permissionSetEntityList = new ArrayList<>(16);
        for (ChartEntity setEntity : list) {
            Long setId = setEntity.getId();
            List<IdNamePojo> permissionList = performanceHelp.getPermissionList(setEntity);

            if (Objects.equals(statisticsType,StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())){
                // 判断选择的员工/部门是否在该指标的考核对象内
                if (companyStructTypeEnum == CompanyStructTypeEnum.USER
                        && !performanceHelp.checkViewPerformanceSetByUserId(corpid, checkedUserId, permissionList, setId)) {
                    continue;
                } else if (companyStructTypeEnum == CompanyStructTypeEnum.DEPARTMENT
                        && !performanceHelp.checkViewPerformanceSetByDeptId(corpid, checkedDepId, permissionList, setId)) {
                    continue;
                }
            }

            permissionSetEntityList.add(setEntity);

            // 考核方式：1动态数值型,2固定数值型
            PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(setEntity);
            Integer assessType = explainPojo.getAssessType();
            if (assessType == AssessTypeEnum.FIXED.getCode()) {
                // 固定数值型
                JSONObject jsonObject = new JSONObject();
                jsonObject.putAll(fixedData(corpid, setEntity, explainPojo));
                idObjMap.put(setId, jsonObject);
            } else {
                /*
                 * 动态数值型，需去业绩目标表查询设置的目标数据
                 */
                // 统一查询tb_performance表内员工的业绩目标值
                setIdIn.add(setId);
                idSetMap.put(setId, setEntity);
            }
        }
        // 转化前端传参为pojo
        PerformancePojo performancePojo = new PerformancePojo();
        BeanUtil.copyProperties(performanceDetailDTO, performancePojo);
        performancePojo.setUserId(checkedUserId);
        performancePojo.setDepartmentId(checkedDepId);

        // 此处查出来的都是动态数值型的业绩目标
        if (setIdIn.size() > 0) {
            List<PerformanceEntity> performanceList = getPerformanceList(corpid, performancePojo, setIdIn);
            for (PerformanceEntity performanceEntity : performanceList) {
                Long setId = performanceEntity.getSetId();
                ChartEntity setEntity = idSetMap.get(setId);
                if(setEntity == null) {
                    continue;
                }
                PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(setEntity);

                JSONObject jsonObject = changeData(corpid, setEntity, explainPojo.getMinCycle(), performancePojo, performanceEntity, StringConstant.DETAIL);
                idObjMap.put(setId, jsonObject);
            }
        }
        JSONArray resultArray = new JSONArray();
        for (ChartEntity setEntity : permissionSetEntityList) {
            Long setId = setEntity.getId();

            PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(setEntity);

            JSONObject jsonObject = idObjMap.get(setId);
            if (jsonObject == null) {
                /*
                 * 如果为null，则说明肯定是动态数值，而员工未设置该指标的目标值。因为：
                 * （1）固定数值已经处理过，并塞入
                 * （2）动态数值，可能当前筛选的员工/部门并未设置其目标，所以还没塞入处理后的jsonObject，因此需要初始化
                 */
                jsonObject = changeData(corpid, setEntity, explainPojo.getMinCycle(), performancePojo, null, StringConstant.DETAIL);
            }
            resultArray.add(jsonObject);
        }

        detailVO.setList(resultArray);
        detailVO.setPageHelper(pageHelper);
        return detailVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PerformanceAggDepartmentVO aggDepartment(PerformanceAggDepartmentDTO performanceAggDepartmentDTO) throws XbbException {
        PerformanceAggDepartmentVO aggDepartmentVO = new PerformanceAggDepartmentVO();

        // TODO 缓存锁先不考虑
        String corpid = performanceAggDepartmentDTO.getCorpid();
        String userId = performanceAggDepartmentDTO.getUserId();
        Integer aggLeaveMark = performanceAggDepartmentDTO.getAggLeaveMark();
        UserEntity userEntity = userModel.getByKey(userId, corpid);
        if (userEntity == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100004, SystemErrorCodeEnum.API_ERROR_100004.getMsg());
        }

        Long setId = performanceAggDepartmentDTO.getSetId();
        Integer year = performanceAggDepartmentDTO.getYear();
        Integer month = performanceAggDepartmentDTO.getMonth();
        if (year == null) {
            // 脚本执行结束，删除缓存锁
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240028);
        }
        // 获取目标实体
        ChartEntity setEntity = performanceHelp.getSetEntity(performanceAggDepartmentDTO.getStatisticsType(),corpid,performanceAggDepartmentDTO.getSetId());

        // 考核方式：1动态数值型,2固定数值型
        PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(setEntity);
        Integer assessType = explainPojo.getAssessType();

        if (assessType == AssessTypeEnum.FIXED.getCode()) {
            // 脚本执行结束，删除缓存锁
            // 考核方式为固定数值的，无需汇总
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240010, PerformanceErrorCodeEnum.API_ERROR_240010.getMsg());
        }
        Integer minCycle = explainPojo.getMinCycle();
        if (month != null && MinCycleEnum.WEEK.getCode() == minCycle) {
            // month不为null（且指标最小考核周期是周），说明是周目标，要把自然年处理成财年年份
            int startMonth = companyConfigModel.getFiscalStartMonth(corpid);
            year = DateUtil.getFiscalYearByMonth(year, month, startMonth);
        }
        List<IdNamePojo> permissionList = performanceHelp.getPermissionList(setEntity);

        // 从缓存读该指标考核的所有部门ids
        List<Long> depIdIn = performanceSetService.getPermission2DepIdsRetainSub(userEntity, setId, permissionList);
        depIdIn.remove(-1L);
        List<Long> depIdList = performanceAggDepartmentDTO.getDepIdList();
        if (CollectionUtils.isNotEmpty(depIdList)) {
            depIdIn.retainAll(depIdList);
        }
        if (depIdIn.size() == 0) {
            // 脚本执行结束，删除缓存锁
            // 没有要处理的部门
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240017, PerformanceErrorCodeEnum.API_ERROR_240017.getMsg());
        }
        // 所有下属员工ids
        Integer dataPermission = userModel.getDataPermission(userEntity, true);
        List<String> subUserIdIn = userModel.getSubIdListByDataPermission4Visible(dataPermission, userId, corpid, BasicConstant.ONE, true);
        if (subUserIdIn.size() == 0) {
            // 脚本执行结束，删除缓存锁
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240017, PerformanceErrorCodeEnum.API_ERROR_240017.getMsg());
        }
        subUserIdIn.add(userEntity.getUserId());

        // 部门id--该部门下的所有员工ids（包含子部门，且与下属取交集）
        Map<Long, List<String>> depUserIdsMap = new HashMap<>(16);
        // 此时的departmentList，肯定都在该指标的考核对象内
        List<DepartmentEntity> departmentList = departmentModel.getByDepIdIn(corpid, depIdIn);
        // 要参与汇总的员工ids
        Set<String> sumUserIdIn = new HashSet<>();
        // 要汇总的部门ids
        Set<Long> sumDepIdIn = new HashSet<>();
        // depId--depName
        Map<Long, String> nameDepMap = new HashMap<>(16);
        for (DepartmentEntity department : departmentList) {
            List<Long> deptmentIdIn = new ArrayList<>();
            Long depId = department.getId();
            deptmentIdIn.add(department.getId());
            // 处理该部门的员工，1包含离职员工
//            List<String> uidInSet = userModel.getUserIdsRecursionDep(deptmentIdIn, corpid, 1);
            // 处理该部门的员工，1包含离职员工，不包含不在可见范围员工
            List<Long> depIdSet = departmentModel.getSubDepIdList(corpid, deptmentIdIn, false);
            List<String> uidInSet = userModel.getDepUserIdList4Visible(corpid, depIdSet, aggLeaveMark);
            // 与下属取交集
            uidInSet.retainAll(subUserIdIn);
            if (uidInSet.size() == 0) {
                continue;
            }
            sumUserIdIn.addAll(uidInSet);
            sumDepIdIn.add(depId);
            depUserIdsMap.put(depId, uidInSet);
            nameDepMap.put(depId, department.getName());
        }
        sumUserIdIn.remove("-1");
        if (sumUserIdIn.size() == 0) {
            // 脚本执行结束，删除缓存锁
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240017, PerformanceErrorCodeEnum.API_ERROR_240017.getMsg());
        }
        /*
         * 查询参与汇总的员工的目标
         */
        Map<String, Object> param = new HashMap<>(16);
        param.put("corpid", corpid);
        param.put("del", DelEnum.NORMAL.getDel());
        param.put("setId", setId);
        param.put("year", year);
        param.put("objectiveType", CompanyStructTypeEnum.USER.getCode());
        param.put("userIdIn", sumUserIdIn);
        List<PerformanceEntity> performanceList = performanceModel.findEntitys(param);
        if (performanceList == null || performanceList.size() == 0) {
            // 脚本执行结束，删除缓存锁
            // 所有人都未设置目标，无需处理
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240018, PerformanceErrorCodeEnum.API_ERROR_240018.getMsg());
        }
        // userId--目标对象
        Map<String, JSONObject> userTargetMap = new HashMap<>(61);
        for (PerformanceEntity entity : performanceList) {
            String userId1 = entity.getUserId();
            JSONObject targetObject = entity.getTarget();
            userTargetMap.put(userId1, targetObject);
        }
        /*
         * 查询出要汇总的部门的目标（即已经设置过目标的目标，要做更新动作，否则插入）
         */
        param.remove("userIdIn");
        param.put("objectiveType", CompanyStructTypeEnum.DEPARTMENT.getCode());
        param.put("depIdIn", sumDepIdIn);
        List<PerformanceEntity> depList = performanceModel.findEntitys(param);
        // 部门id--目标实体
        Map<Long, PerformanceEntity> depPerforMap = new HashMap<>(16);
        for (PerformanceEntity entity : depList) {
            depPerforMap.put(entity.getDepartmentId(), entity);
        }

        /*
         * 为要汇总目标的部门进行处理：求和所属员工的目标和
         * 注：此时的所属员工是这样得到的--该指标的所有考核对象与登录员工下属取交集
         */
        long now = DateUtil.getInt();
        Integer companyStructType = CompanyStructTypeEnum.DEPARTMENT.getCode();
        List<PerformanceEntity> batchEntityList = new ArrayList<>();
        int totalCount = 0;
        int updateCount = 0;
        StringBuffer memo = new StringBuffer();
        for (Long depId : sumDepIdIn) {
            List<String> uidInSet = depUserIdsMap.get(depId);
            if (uidInSet == null || uidInSet.size() == 0) {
                continue;
            }
            JSONObject targetObject = sumUserTarget4Dep(uidInSet, userTargetMap);
            if (targetObject.size() == 0) {
                // 未设置，无需处理
                continue;
            }

            if (memo.length() == 0) {
                memo.append("“" + nameDepMap.get(depId) + "”");
            }
            totalCount++;
            PerformanceEntity entity = depPerforMap.get(depId);
            if (entity == null) {
                entity = new PerformanceEntity();
                entity.setCorpid(corpid);
                entity.setSetId(setId);
                entity.setObjectiveType(companyStructType);
                entity.setDepartmentId(depId);
                entity.setYear(year);
                entity.setAddTime(now);
                entity.setUpdateTime(now);
                // 处理target
                entity.setTarget(targetObject);
                entity.setDel(DelEnum.NORMAL.getDel());
                entity.setStatisticsType(performanceAggDepartmentDTO.getStatisticsType());
                batchEntityList.add(entity);
            } else {
                entity.setUpdateTime(now);
                // 处理target
                entity.setTarget(targetObject);
                try {
                    performanceModel.update(entity);
                } catch (Exception e) {
                    LOG.error("更新目标指标失败", e);
                    throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                }
                updateCount++;
            }

        }
        memo.append("等" + totalCount + "个部门计算了业绩。");
        if (batchEntityList.size() > 0) {
            try {
                performanceModel.insertBatch(batchEntityList);
            } catch (Exception e) {
                LOG.error("保存业绩目标指标失败", e);
                throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
            }

        }
        // 脚本执行结束，删除缓存锁

        // 日志
        String opUserName = performanceAggDepartmentDTO.getLoginUserName();
        String opMemo = userEntity.getName() + "一键汇总了：“" + setEntity.getName() + "”指标" + year + "财年的业绩。其中为" + memo
                + "共更新了" + updateCount + "条数据，插入了" + batchEntityList.size() + "条数据";
        mongoLogHelp.buildLog(corpid, performanceAggDepartmentDTO.getUserId(), opUserName, OperateModuleTypeEnum.PerformanceObject, OperateTypeEnum.SET, "", OtherSetEnum.GOAL_MANAGEMENT.getName(), opMemo, performanceAggDepartmentDTO.getHttpHeader());
        return aggDepartmentVO;
    }


    /**
     * 判断移动端是否可以设置业绩目标
     *
     * @param userEntity 员工
     * @return
     */
    @Override
    public Boolean canSetPerformanceInMobile(UserEntity userEntity) {
        Boolean appSet;
        int datePermission = userModel.getDataPermission(userEntity, true);
        if (datePermission == DataPermissionEnum.ALL.getCode()) {
            appSet = true;
        } else if (datePermission == DataPermissionEnum.SELF.getCode()) {
            // 普通销售角色
            CompanyConfigHasBeenEnableDTO hasBeenEnableDTO = new CompanyConfigHasBeenEnableDTO();
            hasBeenEnableDTO.setCorpid(userEntity.getCorpid());
            hasBeenEnableDTO.setAlias(CompanyConfigEnum.PERFORMANCE_SET.getAlias());
            try {
                CompanyConfigHasBeenEnableVO hasBeenEnableVO = companyConfigService.hasBeenEnable(hasBeenEnableDTO);
                appSet = hasBeenEnableVO.getEnable().equals(BasicConstant.IS_USE);
            } catch (XbbException e) {
                appSet = false;
            }
        } else {
            // 主管角色
            CompanyConfigHasBeenEnableDTO hasBeenEnableDTO = new CompanyConfigHasBeenEnableDTO();
            hasBeenEnableDTO.setCorpid(userEntity.getCorpid());
            hasBeenEnableDTO.setAlias(CompanyConfigEnum.PERFORMANCE_MANAGE_SET.getAlias());
            try {
                CompanyConfigHasBeenEnableVO hasBeenEnableVO = companyConfigService.hasBeenEnable(hasBeenEnableDTO);
                appSet = hasBeenEnableVO.getEnable().equals(BasicConstant.IS_USE);
            } catch (XbbException e) {
                appSet = false;
            }
        }
        return appSet;
    }

    /**
     * 固定数值型
     *
     * @param corpid      公司id
     * @param setEntity   指标实体
     * @param explainPojo 指标扩展字段
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 14:06
     * @version v1.0
     * @since v1.0
     */
    private JSONObject fixedData(String corpid, ChartEntity setEntity, PerformanceSetExplainPojo explainPojo) throws XbbException {
        /*********************固定数值型*********************/
        Double fixedValue = explainPojo.getFixedValue();
        String unit = performanceHelp.setUnit(setEntity);

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("name", setEntity.getName());
        // 固定数值型
        jsonObject.put("assessType", AssessTypeEnum.FIXED.getCode());
        // 单位
        jsonObject.put("unit", unit);
        // 最小考核周期
        Integer minCycle = explainPojo.getMinCycle();
        jsonObject.put("minCycle", minCycle);
        // 最小考核周期
        MinCycleEnum minCycleEnum = MinCycleEnum.getByCode(minCycle);
        if(minCycleEnum == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240022);
        }
        String minCycleStr = minCycleEnum.getName();
        // 考核方式：1动态数值型,2固定数值型
        // 固定数值型，封装成：“每人每月的目标：n次”
        String fixedValueStr = "每人" + minCycleStr + "的目标：" + StringUtil.formatDouble(fixedValue) + " " + unit;
        jsonObject.put("data", fixedValueStr);
        // 求和全年、月
        try {
            jsonObject = getFixedTotal(jsonObject, minCycleEnum, fixedValue, unit, corpid);
        } catch (XbbException e) {
            LOG.error("获取业绩目标工作天数配置失败", e);
        }

        return jsonObject;
    }

    /**
     * 汇总固定频率的目标
     *
     * @param jsonObject   数据封装如的JSONObject
     * @param minCycleEnum 最小考核周期
     * @param fixedValue   指标的固定频率值
     * @param unit         单位
     * @param corpid       公司id
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 14:08
     * @version v1.0
     * @since v1.0
     */
    private JSONObject getFixedTotal(JSONObject jsonObject, MinCycleEnum minCycleEnum, Double fixedValue, String unit, String corpid) throws XbbException {
        double yearTarget = 0;
        fixedValue = (fixedValue != null) ? fixedValue : 0D;
        switch (minCycleEnum) {
            case MONTH:
                /*
                 * 汇总年目标
                 */
                yearTarget = BasicConstant.MAX_MONTH * fixedValue;
                jsonObject.put("yearMemo", "计算公式：每年目标=每月的固定频率值×12");
                break;
            case WEEK:
                /*
                 * 汇总月目标、年目标
                 */
                //计算公式
                jsonObject.put("monthMemo", "计算公式：每月目标=每周的固定频率值÷每周工作日天数×每月工作日天数");
                jsonObject.put("yearMemo", "计算公式：每年目标=每周的固定频率值÷每周工作日天数×每月工作日天数×12，即月目标×12");

                // 每周工作日天数
                CompanyConfigGetWorkingDayWeekDTO dayWeekDTO = new CompanyConfigGetWorkingDayWeekDTO();
                dayWeekDTO.setCorpid(corpid);
                CompanyConfigGetWorkingDayWeekVO dayWeekVO = companyConfigService.getWorkingDayWeek(dayWeekDTO);
                Double workingDayWeek = dayWeekVO.getWorkingDayWeek();

                // 每月工作日天数
                CompanyConfigGetWorkingDayMonthDTO dayMonthDTO = new CompanyConfigGetWorkingDayMonthDTO();
                dayMonthDTO.setCorpid(corpid);
                CompanyConfigGetWorkingDayMonthVO dayMonthVO = companyConfigService.getWorkingDayMonth(dayMonthDTO);
                Double workingDayMonth = dayMonthVO.getWorkingDayMonth();

                double monthTarget = Arith.div(fixedValue, workingDayWeek) * workingDayMonth;
                jsonObject.put("month", "每人每月目标：" + StringUtil.formatDouble(monthTarget) + " " + unit);
                yearTarget = BasicConstant.MAX_MONTH * monthTarget;
                break;
            case DAY:
                /*
                 * 汇总月目标、年目标
                 */
                // 计算公式
                jsonObject.put("monthMemo", "计算公式：每月目标=每天的固定频率值×每月工作日天数");
                jsonObject.put("yearMemo", "计算公式：每年目标=每天的固定频率值×每月工作日天数×12，即月目标×12");
                // 每月有多少天
                CompanyConfigGetWorkingDayMonthDTO dayMonthDTO1 = new CompanyConfigGetWorkingDayMonthDTO();
                dayMonthDTO1.setCorpid(corpid);
                CompanyConfigGetWorkingDayMonthVO dayMonthVO1 = companyConfigService.getWorkingDayMonth(dayMonthDTO1);
                workingDayMonth = dayMonthVO1.getWorkingDayMonth();
                monthTarget = fixedValue * workingDayMonth;
                jsonObject.put("month", "每人每月目标：" + StringUtil.formatDouble(monthTarget) + " " + unit);
                yearTarget = BasicConstant.MAX_MONTH * monthTarget;
                break;
            default:
                break;
        }
        jsonObject.put("year", "每人每年目标：" + StringUtil.formatDouble(yearTarget) + " " + unit);
        return jsonObject;
    }


    /**
     * 变化数值类型
     *
     * @param corpid            公司id
     * @param setEntity         指标实体
     * @param minCycle          考试周期
     * @param performancePojo   参数
     * @param performanceEntity 目标实体
     * @param type              item、detail
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 15:03
     * @version v1.0
     * @since v1.0
     */
    private JSONObject changeData(String corpid, ChartEntity setEntity, Integer minCycle, PerformancePojo performancePojo, PerformanceEntity performanceEntity, String type) throws XbbException {
        // 动态数值型
        // 业绩类型：1员工的业绩 2部门的业绩
        Integer companyStructType = performancePojo.getCompanyStructType();
        CompanyStructTypeEnum companyStructTypeEnum = CompanyStructTypeEnum.getByCode(companyStructType);
        if (companyStructTypeEnum == CompanyStructTypeEnum.UNKNOWN) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240025);
        }
        Integer year = performancePojo.getYear();
        if (year == null || year == 0) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240028);
        }
        // 财年起始月份
        int startMonth = companyConfigModel.getFiscalStartMonth(corpid);
        // 根据最小考核周期的不同，格式化出结果
        JSONObject tableObject = new JSONObject();
        // 最小考核周期
        MinCycleEnum minCycleEnum = MinCycleEnum.getByCode(minCycle);
        if(minCycleEnum == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240022);
        }
        Integer month = performancePojo.getMonth();
        switch (minCycleEnum) {
            case MONTH:
                if (StringConstant.DETAIL.equals(type)) {
                    /*
                     * 当列表页展示的指标最小考核周期是“周”--此时month不为null，而详情页是展示的所有指标，可能其他指标的最小考核周期是“月”
                     * 即，“源头”是从最小考核周期为“周”的进入，说明传入的是自然年、月，需将年转换成财年
                     */
                    if (month != null) {
                        year = DateUtil.getFiscalYearByMonth(year, month, startMonth);
                    }
                }
                tableObject = itemInitMonth(year, startMonth, performanceEntity, type);
                break;
            case WEEK:
                if (month == null || month == 0) {
                    /*
                     * 当列表页展示的指标最小考核周期是“月”--此时month为null，而详情页是展示的所有指标，可能其他指标的最小考核周期是“周”（需要月份）
                     * 即，“源头”是从最小考核周期为“月”的进入，需要给month赋一个初始值：year财年的第month个月份
                     */
                    if (StringConstant.DETAIL.equals(type)) {
                        // 详情页如果没传月份，则获取当前月，当做财年月使用---财年的第几个月份
                        int monthIndex = DateUtil.getMonth4Someday(DateUtil.getInt());
                        // 财年转换成自然年，财年月份转换成相应自然月
                        year = DateUtil.getNormalYearByFiscalYear(year, monthIndex, startMonth);
                        month = DateUtil.getNormalMonthByFiscalMonth(monthIndex, startMonth);
                    } else {
                        throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.MONTH));
                    }
                }
                tableObject = itemInit4Week(year, startMonth, month, performanceEntity, type);
                break;
            default:
                break;
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("name", setEntity.getName());
        // 动态数值型
        jsonObject.put("assessType", AssessTypeEnum.CHANGE.getCode());
        jsonObject.put("unit", performanceHelp.setUnit(setEntity));
        jsonObject.put("minCycle", minCycle);
        jsonObject.put("data", tableObject);
        return jsonObject;
    }

    /**
     * 初始化最小维度为“月”的指标显示的数据
     *
     * @param year              筛选的年份
     * @param startMonth        财年起始月
     * @param performanceEntity 目标实体
     * @param type              item、detail
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 15:18
     * @version v1.0
     * @since v1.0
     */
    private JSONObject itemInitMonth(Integer year, int startMonth, PerformanceEntity performanceEntity, String type) {
        // 开始封装结果
        JSONObject tableObject = new JSONObject();
        tableObject.put(TimeTypeEnum.YEAR.getAlias(), this.formatArray4Month(year, startMonth, performanceEntity, TimeTypeEnum.YEAR, type));
        tableObject.put(TimeTypeEnum.YEAR_HALF_UP.getAlias(), this.formatArray4Month(year, startMonth, performanceEntity, TimeTypeEnum.YEAR_HALF_UP, type));
        tableObject.put(TimeTypeEnum.YEAR_HALF_DOWN.getAlias(), this.formatArray4Month(year, startMonth, performanceEntity, TimeTypeEnum.YEAR_HALF_DOWN, type));
        tableObject.put(TimeTypeEnum.SEASON.getAlias(), this.formatArray4Month(year, startMonth, performanceEntity, TimeTypeEnum.SEASON, type));
        tableObject.put(TimeTypeEnum.MONTH.getAlias(), this.formatArray4Month(year, startMonth, performanceEntity, TimeTypeEnum.MONTH, type));
        return tableObject;
    }

    /**
     * 处理年目标、上半年目标、下半年目标、季度目标：未设置的求和相应月度目标
     *
     * @param oldTargetObject
     * @param targetObject
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 20:14
     * @version v1.0
     * @since v1.0
     */
    @Override
    public JSONObject dealWithTargetObject(JSONObject oldTargetObject, JSONObject targetObject) throws XbbException {
        mixNewIntoOld4MonthWeek(oldTargetObject, targetObject);
        // 处理年目标、上半年目标、下半年目标：未设置的求和相应月度目标
        oldTargetObject = sumMonth4Years(oldTargetObject, targetObject, TimeTypeEnum.YEAR);
        oldTargetObject = sumMonth4Years(oldTargetObject, targetObject, TimeTypeEnum.YEAR_HALF_UP);
        oldTargetObject = sumMonth4Years(oldTargetObject, targetObject, TimeTypeEnum.YEAR_HALF_DOWN);
        // 处理季度目标：未设置的求和相应月度目标
        oldTargetObject = sumMonth4Seasons(oldTargetObject, targetObject);
        return oldTargetObject;
    }
    @Override
    public PerformanceChartListVO chartList(PerformanceChartListDTO performanceChartListDTO) throws XbbException {
        PerformanceChartListVO performanceChartListVO = new PerformanceChartListVO();
        //从详情页请求的分页、title和操作不需要处理
        Integer fromDetail = performanceChartListDTO.getFromDetail();
        Integer statisticsType = performanceChartListDTO.getStatisticsType();
        // 参数校验
        checkParam(performanceChartListDTO);
        // title
        getTitleArray(performanceChartListVO,fromDetail,statisticsType);

        String corpid = performanceChartListDTO.getCorpid();
        String userId = performanceChartListDTO.getUserId();
        UserEntity userEntity = userModel.getByKey(userId, corpid);
        String platform = performanceChartListDTO.getPlatform();
        HashMap<String,Object> param = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        param.put("corpid",corpid);
        param.put("del",DelEnum.NORMAL.getDel());
        param.put("statisticsType", statisticsType);

        // setEntityList,移动端和详情不分页
        PageHelper pageHelper = new PageHelper();
        List<ChartEntity> list;
        try {
            if (Objects.equals(StatisticsTypeEnum.SYSTEM_STATISTIC.getCode(),statisticsType)){
                String orderByStr = "update_time desc,sort desc, id asc ";
                list = performanceHelp.getViewList(userEntity,orderByStr);
                if (!Objects.equals(fromDetail,BasicConstant.ONE) && !StringConstant.PLATFORM_DINGTALK.equals(platform) && CollectionUtils.isNotEmpty(list)){
                    int page = performanceChartListDTO.getPage();
                    int pageSize = performanceChartListDTO.getPageSize();
                    int totalSize = list.size();
                    list = list.subList((page - 1) * pageSize,(page * pageSize >= list.size()) ? (list.size()) : page * pageSize);
                    pageHelper = PageHelperUtil.initPageHelper(totalSize,page,pageSize, PageConstant.DEFAULT_PAGE_SIZE);
                }
            }else{
                param.put("chartType",ChartTypeEnum.CUSTOMER_PERFORMANCE.getCode());
                param.put("orderByStr","update_time desc");
                if (!Objects.equals(fromDetail,BasicConstant.ONE) && !StringConstant.PLATFORM_DINGTALK.equals(platform)){
                    pageHelper = PageHelperUtil.getPageHelper(param, chartCustomModel, performanceChartListDTO.getPage(),performanceChartListDTO.getPageSize());
                    list = (List<ChartEntity>) PageHelperUtil.getEntityList(param, pageHelper, chartCustomModel);
                }else {
                    list = chartCustomModel.findEntitys(param);
                }
            }
        } catch (Exception e) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240029, PerformanceErrorCodeEnum.API_ERROR_240029.getMsg());
        }

        if (CollectionUtils.isNotEmpty(list)) {
            // 获取用户部门容器
            Map<String, UserEntity> userMap = getUserMap(performanceChartListDTO,list.stream().map(ChartEntity::getCreatorId).collect(Collectors.toList()));
            // 操作
            JSONArray operate =  getOperates(performanceChartListDTO);

            List<PerformanceChartListPojo> pojoList = new ArrayList<>();
            list.forEach(chartEntity -> {
                // pojo赋值
                PerformanceChartListPojo pojo = new PerformanceChartListPojo();
                pojo.setId(chartEntity.getId());
                pojo.setStatisticsType(chartEntity.getStatisticsType());
                pojo.setMemo(chartEntity.getMemo());
                pojo.setUnit(performanceHelp.setUnit(chartEntity));
                // 系统如果有改名称，需要加上旧名称
                StringBuffer nameBuffer = new StringBuffer();
                nameBuffer.append(chartEntity.getName());
                if (Objects.equals(statisticsType,StatisticsTypeEnum.SYSTEM_STATISTIC.getCode())){
                    // 名称包含旧名字
                    if(!Objects.equals(chartEntity.getName(), chartEntity.getOldName())) {
                        nameBuffer.append("(原名：").append(chartEntity.getOldName()).append(")");
                    }
                }
                pojo.setName(nameBuffer.toString());
                // 业绩指标扩展字段
                PerformanceSetExplainPojo explainPojo = performanceHelp.getPerformanceSetExplainPojo(chartEntity);
                pojo.setAssessType(explainPojo.getAssessType());
                pojo.setMinCycle(explainPojo.getMinCycle());
                // 考核部门
                List<IdNamePojo> permissionList = performanceHelp.getPermissionList(chartEntity);
                String depNames = performanceHelp.getPermissions2DepNames(permissionList);
                pojo.setDepNames(depNames);

                // 详情不需要处理
                if (!Objects.equals(fromDetail,BasicConstant.ONE)){
                    pojo.setUpdateTime(chartEntity.getUpdateTime());
                    pojo.setEnable(chartEntity.getEnable());
                    pojo.setOperate((JSONArray)CloneUtil.deepClone(operate) );
                    JSONObject sourceAttr = chartEntity.getSourceAttr();
                    if(null != sourceAttr){
                        pojo.setSourceAttr(sourceAttr.getString(StringConstant.ATTR_NAME));
                    }
                    JSONObject belongAttr = chartEntity.getBelongAttr();
                    if (null != belongAttr){
                        pojo.setBelongAttr(belongAttr.getString(StringConstant.ATTR_NAME));
                    }
                    JSONObject timeAttr = chartEntity.getTimeAttr();
                    if (null != timeAttr){
                        pojo.setTimeAttr(timeAttr.getString(StringConstant.ATTR_NAME));
                    }
                    UserEntity creator = userMap.get(chartEntity.getCreatorId());
                    if (null != creator){
                        pojo.setCreatorId(creator.getName());
                    }
                }
                pojoList.add(pojo);
            });
            performanceChartListVO.setData(JSONArray.parseArray(JSON.toJSONString(pojoList)));
        }else {
            performanceChartListVO.setData(new JSONArray());
        }
        performanceChartListVO.setPageHelper(pageHelper);
        return performanceChartListVO;
    }

    /**
     * 初始化最小维度为“周”的指标显示的数据
     *
     * @param year              筛选的年份，此处的year是自然年，不是财年
     * @param startMonth        财年起始月
     * @param month             筛选的月份
     * @param performanceEntity 目标实体
     * @param type              item、detail
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 15:29
     * @version v1.0
     * @since v1.0
     */
    private JSONObject itemInit4Week(Integer year, int startMonth, Integer month, PerformanceEntity performanceEntity, String type) {
        // 周目标获取前要判断当前月的当前财年获取到目标对象
        // 获取year年month月所在的财年
        int fiscalYear = DateUtil.getFiscalYearByMonth(year, month, startMonth);
        // 先获取month在财年内是第几个月
        int monthIndex = DateUtil.getFiscalMonth(startMonth, month);
        String key = "m" + monthIndex;
        // 处理目标值
        Double value = -1D;
        if (performanceEntity != null) {
            value = performanceEntity.getTargetValue4YMSW(TimeTypeEnum.MONTH.getAlias(), key);
        }
        // 封装year年month月数据
        JSONObject tableObject = new JSONObject();
        JSONArray monthArray = new JSONArray();
        JSONObject monthObject = new JSONObject();
        monthObject.put("key", key);
        monthObject.put("title", year + "-" + month);
        if (StringConstant.DETAIL.equals(type)) {
            monthObject.put("value", StringUtil.formatDouble(value));
        } else {
            monthObject.put("value", value);
        }
        monthArray.add(monthObject);

        tableObject.put(TimeTypeEnum.MONTH.getAlias(), monthArray);
        // 封装周数据：只获取month月内的几个周
        // 周索引--区间，比如key="w1"，value="07-02至07-08"
        Map<String, String> weekPeriodMap = FiscalYearHelp.getWeekMap4Month(fiscalYear, year, month, startMonth);

        JSONArray weekArray = new JSONArray();
        // 周目标对象
        JSONObject weekTarget = (performanceEntity == null) ? null : performanceEntity.getPerTargetObject4MSW(TimeTypeEnum.WEEK.getAlias());
        for (Map.Entry<String, String> entry : weekPeriodMap.entrySet()) {
            String weekKey = entry.getKey();
            String title = entry.getValue();
            Double valueW = -1D;
            if (performanceEntity != null) {
                valueW = performanceEntity.getTargetValue4MSW(weekTarget, weekKey);
            }
            JSONObject object = new JSONObject();
            object.put("key", weekKey);
            object.put("title", title);
            // 获取周目标值
            if (StringConstant.DETAIL.equals(type)) {
                object.put("value", StringUtil.formatDouble(valueW));
            } else {
                object.put("value", valueW);
            }
            weekArray.add(object);
        }
        tableObject.put(TimeTypeEnum.WEEK.getAlias(), weekArray);
        return tableObject;
    }

    /**
     * 格式化最小考核周期为月的表格内容（标题、目标值<未设置的显示空即可>）--最终返回给前端的数组
     *
     * @param year              财年年份
     * @param startMonth        财年起始月
     * @param performanceEntity 目标实体
     * @param timeTypeEnum      时间类型
     * @param type              item、detail
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 15:20
     * @version v1.0
     * @since v1.0
     */
    private JSONArray formatArray4Month(Integer year, int startMonth, PerformanceEntity performanceEntity, TimeTypeEnum timeTypeEnum, String type) {
        String alias = timeTypeEnum.getAlias();
        JSONArray jsonArray = new JSONArray();
        String title = "";
        switch (timeTypeEnum) {
            case YEAR:
            case YEAR_HALF_UP:
            case YEAR_HALF_DOWN:
                String fiscal = "";
                if (startMonth != 1) {
                    // 财年起始月不是1月，代表设置了财年
                    fiscal = I18nMessageUtil.getMessage(I18nStringConstant.FISCAL_YEAR);
                }
                String name = timeTypeEnum.getName();
                title = year + "年" + fiscal + name;
                Double value = -1D;
                if (performanceEntity != null) {
                    value = performanceEntity.getTargetValue4Y(alias);
                }
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("key", alias);
                jsonObject.put("title", title);
                if (StringConstant.DETAIL.equals(type)) {
                    jsonObject.put("value", StringUtil.formatDouble(value));
                } else {
                    jsonObject.put("value", value);
                }
                jsonArray.add(jsonObject);
                break;
            case SEASON:
                List<String> seasonList = Arrays.asList("", "一季度", "二季度", "三季度", "四季度");
                // 季度目标对象
                JSONObject seaObject = (performanceEntity == null) ? null : performanceEntity.getPerTargetObject4MSW(alias);
                for (int i = 1; i < 5; i++) {
                    // 数据库内第1季的key为s1，以此类推
                    String key = "s" + i;
                    // 标题："一季度",...
                    title = seasonList.get(i);
                    // 该季度目标值
                    Double valueS = -1D;
                    if (performanceEntity != null) {
                        valueS = performanceEntity.getTargetValue4MSW(seaObject, key);
                    }
                    JSONObject seasonObject = new JSONObject();
                    seasonObject.put("key", key);
                    seasonObject.put("title", title);
                    if (StringConstant.DETAIL.equals(type)) {
                        seasonObject.put("value", StringUtil.formatDouble(valueS));
                    } else {
                        seasonObject.put("value", valueS);
                    }
                    jsonArray.add(seasonObject);
                }
                break;
            case MONTH:
                FiscalYearTimePojo fiscalYearTimePojo = new FiscalYearTimePojo();
                fiscalYearTimePojo.setYear(year);
                fiscalYearTimePojo.setTimeType(TimeTypeEnum.YEAR.getCode());
                // 横坐标--月份：业绩目标要获取整年的，因此timeType为年类型即可
                List<String> dateList = FiscalYearHelp.getDateTitleList(fiscalYearTimePojo, TimeTypeEnum.YEAR.getCode(), startMonth);
                // 月度目标对象
                JSONObject monObject = (performanceEntity == null) ? null : performanceEntity.getPerTargetObject4MSW(alias);
                for (int i = 0; i < dateList.size(); i++) {
                    // 数据库内财年第1个月的key为m1，以此类推
                    String key = "m" + (i + 1);
                    //标题："2017-3","2017-4","2017-5",...
                    title = dateList.get(i);
                    String perMonth = title.substring(5);
                    // 该月份目标值
                    Double valueM = -1D;
                    if (performanceEntity != null) {
                        valueM = performanceEntity.getTargetValue4MSW(monObject, key);
                    }
                    JSONObject monthObject = new JSONObject();
                    monthObject.put("key", key);
                    monthObject.put("title", title);
                    if (StringConstant.DETAIL.equals(type)) {
                        monthObject.put("value", StringUtil.formatDouble(valueM));
                    } else {
                        monthObject.put("value", valueM);
                    }
                    monthObject.put("month", perMonth);
                    jsonArray.add(monthObject);
                }
                break;
            default:
                break;
        }
        return jsonArray;
    }

    /**
     * 把新设置的月、周目标值，融合入旧的目标值对象里面的月周目标对象内，如
     * 新设置了12个月份的目标，要把 这12个月份的目标置入旧的目标对象的month对象内
     * 新设置了8月份几个周的目标，要把其加入旧的目标对象内的week对象内
     *
     * @param oldTargetObject 旧对象
     * @param targetObject    新设置的目标对象
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 20:27
     * @version v1.0
     * @since v1.0
     */
    private void mixNewIntoOld4MonthWeek(JSONObject oldTargetObject, JSONObject targetObject) {
        if (oldTargetObject == null) {
            // 没有旧值，说明是新建，把新值直接全部置入即可
            return;
        }
        // 把月份目标融合入旧的值内
        mix4Object(TimeTypeEnum.MONTH, oldTargetObject, targetObject);
        // 最小考核周期为周，则把新设置的周目标融合入旧值（新设置的周覆盖旧的，未更改的还用旧值）
        mix4Object(TimeTypeEnum.WEEK, oldTargetObject, targetObject);
    }

    /**
     * 把季度、月份、周的对象融合入旧的
     *
     * @param timeTypeEnum    代表哪些目标对象SEASON、MONTH、WEEK
     * @param oldTargetObject 旧对象
     * @param targetObject    新设置的目标对象
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 20:28
     * @version v1.0
     * @since v1.0
     */
    private void mix4Object(TimeTypeEnum timeTypeEnum, JSONObject oldTargetObject, JSONObject targetObject) {
        if (targetObject == null) {
            return;
        }
        String alias = timeTypeEnum.getAlias();
        JSONObject object = targetObject.getJSONObject(alias);
        if (object == null) {
            // 新值对象空，不处理
            return;
        }
        // 旧的月度目标
        JSONObject oldObject = oldTargetObject.getJSONObject(alias);
        if (oldObject == null) {
            oldObject = new JSONObject();
        }
        // 前端传来的月度的key集合（目前周的只有一个月）
        Set<String> keySet = object.keySet();
        for (String key : keySet) {
            // 把新设置的融合入旧的值内
            oldObject.put(key, object.get(key));
        }
        oldTargetObject.put(alias, oldObject);
    }

    /**
     * 处理年、上半年、下半年的目标（如果未设置，则汇总相应月业绩）
     *
     * @param oldTargetObject 旧的指标值（编辑时代表之前旧的，如果是新建的，也传前端传入的指标对象即可）
     * @param targetObject    前端传来的目标
     * @param timeTypeEnum    时间类型枚举
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 20:31
     * @version v1.0
     * @since v1.0
     */
    private JSONObject sumMonth4Years(JSONObject oldTargetObject, JSONObject targetObject, TimeTypeEnum timeTypeEnum) throws XbbException {
        if (oldTargetObject == null || oldTargetObject.size() == 0) {
            oldTargetObject = new JSONObject();
            // 没有旧值，说明是新建，把新值直接全部置入即可
            oldTargetObject.putAll(targetObject);
        }
        String alias = timeTypeEnum.getAlias();
        Double newValue = targetObject.getDouble(alias);
        /*
         * 只有新值内的年、半年为空时，才对各月份目标求和
         * （1）新值的年、半年不为null，代表设置了，则用新的
         * （2）否则，代表未传入年、半年目标，需要对月目标进行汇总，以求出相应的年、半年目标
         */
        if (newValue != null && newValue != -1) {
            oldTargetObject.put(alias, newValue);
            // 该年、半年指标值处理过，移除
            targetObject.remove(alias);
            return oldTargetObject;
        }
        /*
         * 为0，说明未设置，则求和相应月目标
         * 此处要用旧的oldTargetObject，因为：
         * （1）新的可能只传来1个月份，其他月份可能已经设置过；或者新的可能只设置了某个月的周，但是其他月份的周也可能设置过了
         * （2）已经通过方法mixNewIntoOld4MonthWeek()把新的融合进入旧的
         */
        String mAlias = TimeTypeEnum.MONTH.getAlias();
        JSONObject monthObject = oldTargetObject.getJSONObject(mAlias);
        if (monthObject == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240004, String.format(PerformanceErrorCodeEnum.API_ERROR_240004.getMsg(), "月度目标"));
        }
        Double valueTotal = 0D;
        // 月度目标的key
        for (int i = BasicConstant.MIN_MONTH; i <= BasicConstant.MAX_MONTH; i++) {
            if (TimeTypeEnum.YEAR_HALF_UP == timeTypeEnum && i > 6) {
                // 后6个无需加上去
                break;
            } else if (TimeTypeEnum.YEAR_HALF_DOWN == timeTypeEnum && i < 7) {
                // 前6个无需加上去
                continue;
            }
            String key = "m" + i;
            Double value = monthObject.getDouble(key);
            if (value == null) {
                // 未设置，则置入-1D
                value = -1D;
                monthObject.put(key, value);
            }
            value = (value == -1D) ? Double.valueOf(0D) : value;
            valueTotal += value;
        }
        oldTargetObject.put(mAlias, monthObject);
        oldTargetObject.put(alias, valueTotal);
        return oldTargetObject;
    }

    /**
     * 处理各个季度的目标（如果未设置，则汇总相应月业绩）
     *
     * @param oldTargetObject 旧的指标值（编辑时代表之前旧的，如果是新建的，也传前端传入的指标对象即可）
     * @param targetObject    前端传来的目标
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 20:33
     * @version v1.0
     * @since v1.0
     */
    private JSONObject sumMonth4Seasons(JSONObject oldTargetObject, JSONObject targetObject) throws XbbException {
        if (oldTargetObject == null) {
            // 没有旧值，说明是新建，把新值直接全部置入即可
            oldTargetObject = new JSONObject();
        }
        /*
         * 此处要用旧的oldTargetObject，因为：
         * （1）新的可能只传来1个月份，其他月份可能已经设置过；或者新的可能只设置了某个月的周，但是其他月份的周也可能设置过了
         * （2）已经通过方法mixNewIntoOld4MonthWeek()把新的融合进入旧的
         */
        String mAlias = TimeTypeEnum.MONTH.getAlias();
        JSONObject monthObject = oldTargetObject.getJSONObject(mAlias);
        if (monthObject == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240004, String.format(PerformanceErrorCodeEnum.API_ERROR_240004.getMsg(), "月度目标"));
        }
        String seasonAlias = TimeTypeEnum.SEASON.getAlias();
        JSONObject seasonObject = targetObject.getJSONObject(seasonAlias);
        if (seasonObject == null) {
            seasonObject = new JSONObject();
        }
        for (int i = 1; i <= 4; i++) {
            String seasonKey = "s" + i;
            Double newValue = seasonObject.getDouble(seasonKey);
            /*
             * 如果新的指标设置了，则无需求和月目标，直接用新的值即可
             * 否则，要对月目标进行汇总，以求出相应的季度目标
             */
            if (newValue != null && newValue != -1) {
                // 用户设置过该季度目标，无需求和月目标，直接使用用户设置的值
                seasonObject.put(seasonKey, newValue);
                continue;
            }
            // 为0，说明未设置，则求和相应3个月的目标
            Double valueTotal = 0D;
            for (int j = 1; j <= 3; j++) {
                String mKey = "m" + ((i - 1) * 3 + j);
                Double value = monthObject.getDouble(mKey);
                if (value == null) {
                    //未设置，则置入-1D
                    value = -1D;
                    monthObject.put(mKey, value);
                    oldTargetObject.put(mAlias, monthObject);
                }
                value = (value == -1) ? Double.valueOf(0D) : value;
                valueTotal += value;
            }
            seasonObject.put(seasonKey, valueTotal);
        }
        oldTargetObject.put(seasonAlias, seasonObject);
        return oldTargetObject;
    }

    /**
     * web端、app端目标保存逻辑
     *
     * @param performanceSaveWebDTO 保存参数dto
     * @param minCycle              最小考核周期：1每月,2每周,3每天
     * @param chartName             指标名称
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 20:08
     * @version v1.0
     * @since v1.0
     */
    private void saveTarget(PerformanceSaveWebDTO performanceSaveWebDTO, Integer minCycle, String chartName) throws XbbException {
        String corpid = performanceSaveWebDTO.getCorpid();
        // 指标id
        Long setId = performanceSaveWebDTO.getSetId();
        JSONObject targetObject = performanceSaveWebDTO.getTarget();

        // 最小考核周期：1每月,2每周,3每天
        MinCycleEnum minCycleEnum = MinCycleEnum.getByCode(minCycle);
        if(minCycleEnum == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240022);
        }
        // 目标保存：根据最小考核周期的不同，向上汇总
        long now = DateUtil.getInt();
        Integer companyStructType = performanceSaveWebDTO.getCompanyStructType();
        /*
         * 需要注意--对于year参数，根据最小考核周期的不同，则代表不同的含义：
         * （1）最小考核周期为“月”，则year代表财年。例如，传入2018，则代表是2018财年，实际当前时间可能才在2017年
         * （2）最小考核周期为“周”，则year代表自然年，结合“month”参数，如果year=2018，month=7，就是代表的18年7月
         * 另外，tb_performance表内的year是财年
         */
        Integer year = performanceSaveWebDTO.getYear();
        Map<String, Object> param = new HashMap<>(16);
        param.put("corpid", corpid);
        param.put("del", DelEnum.NORMAL.getDel());
        param.put("setId", setId);
        param.put("objectiveType", companyStructType);
        if (MinCycleEnum.WEEK == minCycleEnum) {
            // 需要通过year和month，获取财年年份
            Integer month = performanceSaveWebDTO.getMonth();
            if (month == null) {
                throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), I18nMessageUtil.getMessage(I18nStringConstant.MONTH));
            }
            // 财年起始月份
            int startMonth = companyConfigModel.getFiscalStartMonth(corpid);
            Integer fiscalYear = DateUtil.getFiscalYearByMonth(year, month, startMonth);
            year = fiscalYear;
        }
        param.put("year", year);
        // 存放已经处理过的员工id列表
        Set<String> updateUidSet = new HashSet<>();
        // 存放已经处理过的部门id列表
        Set<Long> updateDidSet = new HashSet<>();
        // 存放要插入的list
        List<PerformanceEntity> insertList = new ArrayList<>();
        String memo = "";
        String opUserName = performanceSaveWebDTO.getLoginUserName();
        // 员工业绩
        if (companyStructType == CompanyStructTypeEnum.USER.getCode()) {
            List<String> userIdIn = performanceSaveWebDTO.getUserIdIn();
            memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_PERFORMANCE_SAVE_TARGET),opUserName,chartName,userIdIn.size(),CompanyStructTypeEnum.USER.getName());
            param.put("userIdIn", userIdIn);
            List<PerformanceEntity> list = performanceModel.findEntitys(param);
            // 先处理需要更新的
            if (list != null) {
                this.updateTarget(minCycleEnum, targetObject, now, list, updateUidSet, updateDidSet);
            }
            // 接下来处理批量插入的（需要用set防止重复）
            Set<String> noRepeat = new HashSet<>(userIdIn);
            // 去掉已经更新过的
            noRepeat.removeAll(updateUidSet);
            if (noRepeat.size() > 0) {
                /*
                 * 汇总年、半年、季度目标（如果这三个顶层的未设置，则汇总计算出来）
                 * 插入的，所以旧的新的都传targetObject
                 */
                targetObject = dealWithTargetObject(null, targetObject);
                for (String uid : noRepeat) {
                    PerformanceEntity entity = new PerformanceEntity();
                    entity.setCorpid(corpid);
                    entity.setSetId(setId);
                    entity.setObjectiveType(companyStructType);
                    entity.setUserId(uid);
                    entity.setYear(year);
                    // 插入，直接塞入即可，不用处理target
                    entity.setTarget(targetObject);
                    entity.setAddTime(now);
                    entity.setUpdateTime(now);
                    entity.setDel(DelEnum.NORMAL.getDel());
                    entity.setStatisticsType(performanceSaveWebDTO.getStatisticsType());
                    insertList.add(entity);
                }
                if (insertList.size() > 0) {
                    try {
                        performanceModel.insertBatch(insertList);
                    } catch (Exception e) {
                        LOG.error("保存业绩目标指标失败", e);
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                    }
                }
            }
        } else if (companyStructType == CompanyStructTypeEnum.DEPARTMENT.getCode()) {
            // 部门业绩
            List<Long> depIdIn = performanceSaveWebDTO.getDepIdIn();
            memo = String.format(I18nMessageUtil.getMessage(LogMemoConstant.LOG_MEMO_PERFORMANCE_SAVE_TARGET),opUserName,chartName,depIdIn.size(),CompanyStructTypeEnum.DEPARTMENT.getName());
            param.put("depIdIn", depIdIn);
            List<PerformanceEntity> list = performanceModel.findEntitys(param);
            // 先处理需要更新的
            if (list != null) {
                this.updateTarget(minCycleEnum, targetObject, now, list, updateUidSet, updateDidSet);
            }
            // 接下来处理批量插入的（需要用set防止重复）
            Set<Long> noRepeat = new HashSet<>(depIdIn);
            // 去掉已经更新过的
            noRepeat.removeAll(updateDidSet);
            if (noRepeat.size() > 0) {
                /*
                 * 汇总年、半年、季度目标（如果这三个顶层的未设置，则汇总计算出来）
                 * 插入的，所以旧的新的都传targetObject
                 */
                targetObject = dealWithTargetObject(null, targetObject);
                for (Long did : noRepeat) {
                    PerformanceEntity entity = new PerformanceEntity();
                    entity.setCorpid(corpid);
                    entity.setSetId(setId);
                    entity.setObjectiveType(companyStructType);
                    entity.setDepartmentId(did);
                    entity.setYear(year);
                    entity.setTarget(targetObject);
                    entity.setAddTime(now);
                    entity.setUpdateTime(now);
                    entity.setDel(DelEnum.NORMAL.getDel());
                    entity.setStatisticsType(performanceSaveWebDTO.getStatisticsType());
                    insertList.add(entity);
                }
                if (insertList.size() > 0) {
                    try {
                        performanceModel.insertBatch(insertList);
                    } catch (Exception e) {
                        LOG.error("保存业绩目标指标失败", e);
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                    }
                }
            }
        }
        // 日志
        mongoLogHelp.buildLog(corpid, performanceSaveWebDTO.getUserId(), opUserName, OperateModuleTypeEnum.PerformanceObject, OperateTypeEnum.EDIT, String.valueOf(setId), OtherSetEnum.GOAL_MANAGEMENT.getName(), memo, performanceSaveWebDTO.getHttpHeader());
    }

    /**
     * 更新目标（库内已存在的员工目标进行保存），并且把这些更新的目标的员工id、部门id塞入list，与传入的总的list结合得到哪些是需要插入的
     *
     * @param minCycleEnum 最小考核周期：1每月,2每周,3每天
     * @param targetObject 前端传入的目标参数
     * @param now          时间戳
     * @param list         员工/部门的目标list
     * @param updateUidSet 需要更新目标的员工userId列表
     * @param updateDidSet 需要更新目标的部门id列表
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 19:55
     * @version v1.0
     * @since v1.0
     */
    private void updateTarget(MinCycleEnum minCycleEnum, JSONObject targetObject, long now,
                              List<PerformanceEntity> list, Set<String> updateUidSet, Set<Long> updateDidSet) throws XbbException {
        switch (minCycleEnum) {
            case MONTH:
                // 最小考核周期为月，处理年、半年、季度（没设置则汇总月）
                for (PerformanceEntity performanceEntity : list) {
                    JSONObject oldTargetObject = performanceEntity.getTarget();
                    oldTargetObject = dealWithTargetObject(oldTargetObject, targetObject);
                    updateUidSet.add(performanceEntity.getUserId());
                    updateDidSet.add(performanceEntity.getDepartmentId());

                    performanceEntity.setTarget(oldTargetObject);
                    performanceEntity.setUpdateTime(now);
                    // update不能批量更新
                    try {
                        performanceModel.update(performanceEntity);
                    } catch (Exception e) {
                        LOG.error("更新业绩目标指标失败", e);
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                    }
                }
                break;
            case WEEK:
                JSONObject monthObject = targetObject.getJSONObject(TimeTypeEnum.MONTH.getAlias());
                JSONObject weekObject = targetObject.getJSONObject(TimeTypeEnum.WEEK.getAlias());
                if (monthObject == null) {
                    throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240004, String.format(PerformanceErrorCodeEnum.API_ERROR_240004.getMsg(), "月度目标"));
                }
                if (weekObject == null) {
                    throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240004, String.format(PerformanceErrorCodeEnum.API_ERROR_240004.getMsg(), "周目标"));
                }
                // 前端传来的月度的key集合（目前周的只有一个月）
                Set<String> monthKeySet = monthObject.keySet();
                Set<String> weekKeySet = weekObject.keySet();
                String mAlias = TimeTypeEnum.MONTH.getAlias();
                String wAlias = TimeTypeEnum.WEEK.getAlias();
                for (PerformanceEntity performanceEntity : list) {
                    updateUidSet.add(performanceEntity.getUserId());
                    updateDidSet.add(performanceEntity.getDepartmentId());

                    JSONObject oldTargetObject = performanceEntity.getTarget();
                    // 如果用户已经设置过（年份、季度、其他月份等，则把现在设置的放进去）
                    if (oldTargetObject != null) {
                        // 旧的月度目标
                        JSONObject oldMObject = oldTargetObject.getJSONObject(mAlias);
                        if (oldMObject == null) {
                            oldMObject = new JSONObject();
                        }
                        for (String monthKey : monthKeySet) {
                            // 把新设置的置入旧的值内
                            oldMObject.put(monthKey, monthObject.get(monthKey));
                        }
                        // 旧的周目标
                        JSONObject oldWObject = oldTargetObject.getJSONObject(wAlias);
                        if (oldWObject == null) {
                            oldWObject = new JSONObject();
                        }
                        for (String weekKey : weekKeySet) {
                            oldWObject.put(weekKey, weekObject.get(weekKey));
                        }
                        oldTargetObject.put(mAlias, oldMObject);
                        oldTargetObject.put(wAlias, oldWObject);
                        oldTargetObject = dealWithTargetObject(oldTargetObject, oldTargetObject);
                    }
                    performanceEntity.setTarget(oldTargetObject);
                    performanceEntity.setUpdateTime(now);
                    // update不能批量更新
                    try {
                        performanceModel.update(performanceEntity);
                    } catch (Exception e) {
                        LOG.error("更新业绩目标指标失败", e);
                        throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, SystemErrorCodeEnum.API_ERROR_100001.getMsg());
                    }

                }
                break;
            default:
                break;
        }
    }

    /**
     * 判断传入的目标值是否合法
     *
     * @param targetObject 业绩目标值
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-18 19:37
     * @version v1.0
     * @since v1.0
     */
    private void checkTarget(JSONObject targetObject) throws XbbException {
        // 判断目标是否为空
        if (targetObject == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240004, String.format(PerformanceErrorCodeEnum.API_ERROR_240004.getMsg(), "业绩目标"));
        }
        // 获取时间维度名称的集合，如year,yearHalfUp,season,month
        Set<String> keySet = targetObject.keySet();
        // 判断最小考核周期
        for (String key : keySet) {
            if ("year".equals(key) || "yearHalfUp".equals(key) || "yearHalfDown".equals(key)) {
                String periodTarget = targetObject.getString(key);
                if (!StringUtil.isEmpty(periodTarget) && !periodTarget.matches(RegExConstant.PERFORMANCE_TARGET)) {
                    throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240015, String.format(PerformanceErrorCodeEnum.API_ERROR_240015.getMsg(), "目标值", "目标值"));
                }
            } else if ("season".equals(key) || "month".equals(key) || "week".equals(key)) {
                JSONObject periodObject = targetObject.getJSONObject(key);
                if (periodObject == null) {
                    continue;
                }
                // 获取到时间维度的下一级名称，如s1,s2,m1,m2,w1,w2
                Set<String> periodKeySet = periodObject.keySet();
                for (String periodKey : periodKeySet) {
                    String periodTarget = periodObject.getString(periodKey);
                    if (!StringUtil.isEmpty(periodTarget) && !periodTarget.matches(RegExConstant.PERFORMANCE_TARGET)) {
                        throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240015, String.format(PerformanceErrorCodeEnum.API_ERROR_240015.getMsg(), "目标值", "目标值"));
                    }
                }
            }
        }
    }

    /**
     * 获取动态数值型的目标列表
     *
     * @param * @param null
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-19 11:20
     * @version v1.0
     * @since v1.0
     */
    private JSONObject dynamicList(UserEntity userEntity, ChartEntity setEntity, Integer minCycle, PerformanceListDTO listDTO) throws XbbException {
        String corpid = listDTO.getCorpid();
        // 业绩类型：1员工的业绩 2部门的业绩
        Integer companyStructType = listDTO.getCompanyStructType();
        CompanyStructTypeEnum companyStructTypeEnum = CompanyStructTypeEnum.getByCode(companyStructType);
        if (companyStructTypeEnum == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, String.format(PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), "业绩类型"));
        }
        Integer year = listDTO.getYear();
        if (year == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, String.format(PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), "财年年份"));
        }
        // 财年起始月份
        int startMonth = companyConfigModel.getFiscalStartMonth(corpid);
        Integer month = listDTO.getMonth();
        Integer fiscalYear = year;

        Integer page = listDTO.getPage();
        Integer pageSize = listDTO.getPageSize();
        pageSize = (pageSize == null) ? PageHelper.PAGE_SIZE : pageSize;
        // 筛选的员工或部门id
        String checkedUserId = listDTO.getCheckedUserId();
        Long checkedDepId = listDTO.getCheckedDepId();

        /*
         * 需要注意--对于year参数，根据最小考核周期的不同，则代表不同的含义：
         * （1）最小考核周期为“月”，则year代表财年。例如，传入2018，则代表是2018财年，实际当前时间可能才在2017年
         * （2）最小考核周期为“周”，则year代表自然年，结合“month”参数，如果year=2018，month=7，就是代表的18年7月
         * 另外，tb_performance表内的year是财年
         */
        Map<String, Object> param = new HashMap<>(16);
        param.put("corpid", corpid);
        param.put("del", DelEnum.NORMAL.getDel());
        param.put("setId", setEntity.getId());
        param.put("objectiveType", companyStructType);
        param.put("year", year);
        param.put("statisticsType",listDTO.getStatisticsType());
        // 最小考核周期
        MinCycleEnum minCycleEnum = MinCycleEnum.getByCode(minCycle);
        if(minCycleEnum == null) {
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, "考核周期不正确");
        }
        if (MinCycleEnum.WEEK == minCycleEnum) {
            // 需要通过year和month，获取财年年份
            if (month == null) {
                throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, String.format(PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), "月份"));
            }
            // 计算出财年年份
            fiscalYear = DateUtil.getFiscalYearByMonth(year, month, startMonth);
            param.put("year", fiscalYear);
        }
        param.put("page", page);

        PageHelper pageHelper = null;
        List<PerformanceEntity> list = null;
        // userId--员工姓名
        Map<String, String> nameUserMap = new HashMap<>(16);
        // userId--员工所在部门名称合集
        Map<String, String> nameUserDepsMap = new HashMap<>(16);
        // 部门id--部门名称
        Map<Long, String> nameDepMap = new HashMap<>(16);
        // 处理变化数值类型的标题
        JSONArray titleArray = new JSONArray();

        List<IdNamePojo> permissionList = performanceHelp.getPermissionList(setEntity);

        switch (companyStructTypeEnum) {
            case USER:
                // 员工目标列表的标题
                titleArray.add(BasicHelper.formatTitle("name", I18nMessageUtil.getMessage(I18nStringConstant.NAME)));
                titleArray.add(BasicHelper.formatTitle("depName", I18nMessageUtil.getMessage(CommonConstant.DEPARTMENT)));
                titleArray.add(BasicHelper.formatTitle("year", I18nMessageUtil.getMessage(I18nStringConstant.FULL_YEAR_GOAL)));
                //考核的员工id列表
                Set<String> userIdIn = performanceSetService.getPermission2UserIdsRetainSub(userEntity, setEntity.getId(), permissionList, nameDepMap);
                if (!StringUtil.isEmpty(checkedUserId)) {
                    if (!userIdIn.contains(checkedUserId)) {
                        throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240012, String.format(PerformanceErrorCodeEnum.API_ERROR_240012.getMsg(), "员工"));
                    }
                    userIdIn.clear();
                    userIdIn.add(checkedUserId);
                    userIdIn.add(StringConstant.NEGATIVE_NUMBER);
                }
                //先将离职人员过滤掉
                userIdIn = userModel.filterOutDepartingUser(userIdIn, userEntity.getCorpid());

                param.put("userIdIn", userIdIn);
                pageHelper = PageHelperUtil.getPageHelper(param, performanceModel, pageSize);
                list = (List<PerformanceEntity>) PageHelperUtil.getEntityList(param, pageHelper, performanceModel);
                // 清空userIdIn，以塞入新的员工id列表（分页后就获取几个员工即可）
                userIdIn.clear();
                for (PerformanceEntity entity : list) {
                    userIdIn.add(entity.getUserId());
                }
                List<String> userIdList = new ArrayList<>(userIdIn);
                if (userIdList.size() == 0) {
                    userIdList.add("-1");
                }
                // 员工列表
                List<UserEntity> userList = userModel.findEntitysByUserIds(userIdList, userEntity.getCorpid());
                for (UserEntity entity : userList) {
                    String uid = entity.getUserId();
                    String name = entity.getName();
                    nameUserMap.put(uid, name);
                    String depName = performanceSetService.getDepNames4User(nameDepMap, entity);
                    nameUserDepsMap.put(uid, depName);
                }
                break;
            case DEPARTMENT:
                list = new ArrayList<>();
                // 员工目标列表的标题
                titleArray.add(BasicHelper.formatTitle("depName", I18nMessageUtil.getMessage(CommonConstant.DEPARTMENT)));
                titleArray.add(BasicHelper.formatTitle("year", I18nMessageUtil.getMessage(I18nStringConstant.FULL_YEAR_GOAL)));
                List<Long> depIdSet = performanceSetService.getPermission2DepIdsRetainSub(userEntity, setEntity.getId(), permissionList);
                if (checkedDepId != null) {
                    if (!depIdSet.contains(checkedDepId)) {
                        throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240012, String.format(PerformanceErrorCodeEnum.API_ERROR_240012.getMsg(), "部门"));
                    }
                    // 转化前端传参为pojo
                    PerformancePojo performancePojo = new PerformancePojo();
                    BeanUtil.copyProperties(listDTO, performancePojo);
                    performancePojo.setDepartmentId(checkedDepId);
                    performancePojo.setYear(fiscalYear);
                    performancePojo.setStatisticsType(listDTO.getStatisticsType());
                    // 当前筛选部门的业绩目标
                    PerformanceEntity supPerformanceEntity = performanceModel.getPerformanceEntity(corpid, performancePojo);
                    if (supPerformanceEntity.getId() != null) {
                        // id为null，则说明未设置
                        list.add(supPerformanceEntity);
                    }
                    // 获取下一级的子部门
                    List<DepartmentEntity> subDepartmentList = departmentModel.getSubOneLevel(corpid, checkedDepId);
                    Set<Long> subIdList = new HashSet<>();
                    for (DepartmentEntity departmentEntity : subDepartmentList) {
                        Long depId = departmentEntity.getId();
                        subIdList.add(depId);
                        nameDepMap.put(depId, departmentEntity.getName());
                    }
                    depIdSet.retainAll(subIdList);
                    depIdSet.add(-1L);
                }
                param.put("depIdIn", depIdSet);
                pageHelper = PageHelperUtil.getPageHelper(param, performanceModel, pageSize);
                list.addAll((List<PerformanceEntity>) PageHelperUtil.getEntityList(param, pageHelper, performanceModel));
                // 清空depIdSet，以塞入新的员工id列表（分页后就获取几个员工即可）
                depIdSet.clear();
                for (PerformanceEntity entity : list) {
                    depIdSet.add(entity.getDepartmentId());
                }
                List<DepartmentEntity> departmentList = departmentModel.getByDepIdIn(corpid, depIdSet);
                for (DepartmentEntity entity : departmentList) {
                    nameDepMap.put(entity.getId(), entity.getName());
                }
                break;

            default:
                break;
        }
        // 封装最后表格内data
        JSONArray dataArray = new JSONArray();
        if (MinCycleEnum.WEEK == minCycleEnum) {
            // 周索引--区间，比如key="w1"，value="07-02至07-08"
            Map<String, String> weekPeriodMap = FiscalYearHelp.getWeekMap4Month(fiscalYear, year, month, startMonth);
            for (Map.Entry<String, String> entry : weekPeriodMap.entrySet()) {
                String weekKey = entry.getKey();
                String title = entry.getValue();

                titleArray.add(BasicHelper.formatTitle(weekKey, title));
            }
            if (list != null && list.size() > 0) {
                for (PerformanceEntity entity : list) {
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("id", entity.getId());
                    jsonObject.put("setId", entity.getSetId());
                    if (companyStructTypeEnum == CompanyStructTypeEnum.DEPARTMENT) {
                        Long depId = entity.getDepartmentId();
                        // 部门目标
                        jsonObject.put("departmentId", depId);
                        jsonObject.put("depName", nameDepMap.get(depId));
                    } else {
                        // 员工目标
                        String uid = entity.getUserId();
                        jsonObject.put("userId", uid);
                        jsonObject.put("name", nameUserMap.get(uid));
                        jsonObject.put("depName", nameUserDepsMap.get(uid));
                    }
                    Double yearTarget = entity.getTargetValue4Y(TimeTypeEnum.YEAR.getAlias());
                    jsonObject.put("year", StringUtil.formatDouble(yearTarget));
                    // 处理周目标
                    JSONObject targetObjet = entity.getPerTargetObject4MSW(TimeTypeEnum.WEEK.getAlias());
                    for (Map.Entry<String, String> entry : weekPeriodMap.entrySet()) {
                        String weekKey = entry.getKey();
                        jsonObject.put(weekKey, StringUtil.formatDouble(entity.getTargetValue4MSW(targetObjet, weekKey)));
                    }
                    dataArray.add(jsonObject);
                }
            }
        } else {
            FiscalYearTimePojo fiscalYearTimePojo = new FiscalYearTimePojo();
            fiscalYearTimePojo.setYear(year);
            fiscalYearTimePojo.setTimeType(TimeTypeEnum.YEAR.getCode());
            // 横坐标--月份：业绩目标要获取整年的，因此timeType为年类型即可
            List<String> dateList = FiscalYearHelp.getDateTitleList(fiscalYearTimePojo, TimeTypeEnum.YEAR.getCode(), startMonth);
            for (int i = 0; i < dateList.size(); i++) {
                // 数据库内财年第1个月的key为m1，以此类推
                String key = "m" + (i + 1);
                titleArray.add(BasicHelper.formatTitle(key, dateList.get(i)));
            }
            for (PerformanceEntity entity : list) {
                JSONObject jsonObject = new JSONObject();
                jsonObject.put("id", entity.getId());
                jsonObject.put("setId", entity.getSetId());
                if (companyStructTypeEnum == CompanyStructTypeEnum.DEPARTMENT) {
                    // 部门目标
                    Long depId = entity.getDepartmentId();
                    jsonObject.put("departmentId", depId);
                    jsonObject.put("depName", nameDepMap.get(depId));
                } else {
                    // 员工目标
                    String uid = entity.getUserId();
                    jsonObject.put("userId", uid);
                    jsonObject.put("name", nameUserMap.get(uid));
                    jsonObject.put("depName", nameUserDepsMap.get(uid));
                }
                Double yearTarget = entity.getTargetValue4Y(TimeTypeEnum.YEAR.getAlias());
                jsonObject.put("year", StringUtil.formatDouble(yearTarget));
                // 处理月目标
                JSONObject perTarget = entity.getPerTargetObject4MSW(TimeTypeEnum.MONTH.getAlias());
                for (int i = BasicConstant.MIN_MONTH; i <= BasicConstant.MAX_MONTH; i++) {
                    String key = "m" + i;
                    jsonObject.put(key, StringUtil.formatDouble(entity.getTargetValue4MSW(perTarget, key)));
                }
                dataArray.add(jsonObject);
            }
        }
        // 返回数据：标题数组、表格数据数组
        JSONObject resultObject = new JSONObject();
        // 动态数值型
        resultObject.put("assessType", AssessTypeEnum.CHANGE.getCode());
        resultObject.put("unit", setEntity.getOriginalUnit());
        resultObject.put("minCycle", minCycle);
        resultObject.put("title", titleArray);
        resultObject.put("pageHelper", pageHelper);
        resultObject.put("data", dataArray);
        return resultObject;
    }

    /**
     * 通过传入performancePojo，判断是传入财年还是传入自然年，进而获取performanceList
     * 并且将performancePojo中的year置成财年
     *
     * @param corpid          公司id
     * @param performancePojo 目标pojo
     * @param setIdIn         指标Id集合
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-19 20:19
     * @version v1.0
     * @since v1.0
     */
    private List<PerformanceEntity> getPerformanceList(String corpid, PerformancePojo performancePojo, Set<Long> setIdIn) {
        Integer month = performancePojo.getMonth();
        Integer year = performancePojo.getYear();
        List<PerformanceEntity> list;
        if (month != null) {
            // 获取财年起始月份
            int startMonth = companyConfigModel.getFiscalStartMonth(corpid);
            // 传入自然年月
            Integer fiscalYear = DateUtil.getFiscalYearByMonth(year, month, startMonth);
            // 将pojo中的year设置成财年
            performancePojo.setYear(fiscalYear);
            // 获取目标列表
            list = performanceModel.findEntitys(corpid, performancePojo, setIdIn);
            // 将pojo中的year置回自然年
            performancePojo.setYear(year);
            return list;
        } else {
            // 传入财年
            list = performanceModel.findEntitys(corpid, performancePojo, setIdIn);
            return list;
        }
    }

    /**
     * 求和员工目标，以得到部门目标
     *
     * @param uidInSet      该部门的员工ids--注：此时的所属员工是这样得到的--该指标的所有考核对象与登录员工下属取交集
     * @param userTargetMap userId--目标对象
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-20 10:16
     * @version v1.0
     * @since v1.0
     */
    private JSONObject sumUserTarget4Dep(List<String> uidInSet, Map<String, JSONObject> userTargetMap) {
        JSONObject targetObject = new JSONObject();

        Double totalYear = -1D;
        Double totalYearHalfUp = -1D;
        Double totalYearHalfDown = -1D;
        JSONObject totalSeasonObj = new JSONObject();
        JSONObject totalMonthObj = new JSONObject();
        JSONObject totalWeekObj = new JSONObject();
        for (String userId : uidInSet) {
            JSONObject userTargetObject = userTargetMap.get(userId);
            if (userTargetObject == null || userTargetObject.size() == 0) {
                continue;
            }
            // 目标对象的keys，有：year、yearHalfUp、yearHalfDown、season、month、week
            Set<String> keySet = userTargetObject.keySet();
            for (String targetKey : keySet) {
                TimeTypeEnum timeTypeEnum = TimeTypeEnum.getByAlias(targetKey);
                switch (timeTypeEnum) {
                    case YEAR:
                        totalYear = sumTarget(totalYear, userTargetObject, timeTypeEnum);
                        break;
                    case YEAR_HALF_UP:
                        totalYearHalfUp = sumTarget(totalYearHalfUp, userTargetObject, timeTypeEnum);
                        break;
                    case YEAR_HALF_DOWN:
                        totalYearHalfDown = sumTarget(totalYearHalfDown, userTargetObject, timeTypeEnum);
                        break;
                    case SEASON:
                        totalSeasonObj = sumTarget(totalSeasonObj, userTargetObject, timeTypeEnum);
                        break;
                    case MONTH:
                        totalMonthObj = sumTarget(totalMonthObj, userTargetObject, timeTypeEnum);
                        break;
                    case WEEK:
                        totalWeekObj = sumTarget(totalWeekObj, userTargetObject, timeTypeEnum);
                        break;

                    default:
                        break;
                }
            }
        }
        // 汇总完部门的所有员工目标，再塞入
        if (totalYear > 0) {
            targetObject.put(TimeTypeEnum.YEAR.getAlias(), totalYear);
        }
        if (totalYearHalfUp > 0) {
            targetObject.put(TimeTypeEnum.YEAR_HALF_UP.getAlias(), totalYearHalfUp);
        }
        if (totalYearHalfDown > 0) {
            targetObject.put(TimeTypeEnum.YEAR_HALF_DOWN.getAlias(), totalYearHalfDown);
        }
        if (totalSeasonObj.size() > 0) {
            targetObject.put(TimeTypeEnum.SEASON.getAlias(), totalSeasonObj);
        }
        if (totalMonthObj.size() > 0) {
            targetObject.put(TimeTypeEnum.MONTH.getAlias(), totalMonthObj);
        }
        if (totalWeekObj.size() > 0) {
            targetObject.put(TimeTypeEnum.WEEK.getAlias(), totalWeekObj);
        }
        return targetObject;
    }

    /**
     * 求和员工的年、半年目标
     *
     * @param total            年、半年目标
     * @param userTargetObject 员工目标对象
     * @param timeTypeEnum     类型
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-20 10:37
     * @version v1.0
     * @since v1.0
     */
    private Double sumTarget(Double total, JSONObject userTargetObject, TimeTypeEnum timeTypeEnum) {
        Double target = userTargetObject.getDouble(timeTypeEnum.getAlias());
        if (target != null && target != -1) {
            total = (total == -1) ? Double.valueOf(0D) : total;
            total += target;
        }
        return total;
    }

    /**
     * 求和员工的季度、月、周目标
     *
     * @param totalJson        季度、月、周目标对象
     * @param userTargetObject 员工目标对象
     * @param timeTypeEnum     类型
     * @return
     * @throws
     * @author hongxiao
     * @date: 2019-02-20 10:18
     * @version
     * @since
     */
    private JSONObject sumTarget(JSONObject totalJson, JSONObject userTargetObject, TimeTypeEnum timeTypeEnum) {
        JSONObject jsonObject = userTargetObject.getJSONObject(timeTypeEnum.getAlias());
        if (jsonObject != null && jsonObject.size() > 0) {
            Set<String> keySet = jsonObject.keySet();
            for (String key : keySet) {
                Double target = jsonObject.getDouble(key);
                if (target == null || target == -1) {
                    continue;
                }
                Double total = totalJson.getDouble(key);
                total = (total == null || total == -1) ? Double.valueOf(0D) : total;
                total += target;
                totalJson.put(key, total);
            }
        }
        return totalJson;
    }

    /**
     * 参数校验
     * @param performanceChartListDTO
     * @throws XbbException
     */
    private void checkParam(PerformanceChartListDTO performanceChartListDTO) throws XbbException {
        Integer statisticsType = performanceChartListDTO.getStatisticsType();
        String corpid = performanceChartListDTO.getCorpid();
        if (!StatisticsTypeEnum.getStatisticTypes().contains(statisticsType)){
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240030,PerformanceErrorCodeEnum.API_ERROR_240030.getMsg());
        }
        // 套餐
        Integer feeType = packageHelp.getFeeType(corpid);
        if (!Objects.equals(feeType,PackageTypeEnum.ULTIMATE.getType()) && Objects.equals(statisticsType,StatisticsTypeEnum.CUSTOM_STATISTIC.getCode())){
            throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240031,PerformanceErrorCodeEnum.API_ERROR_240031.getMsg());
        }
        String platform = performanceChartListDTO.getPlatform();

        // 移动端：参数判断
        if (StringConstant.PLATFORM_DINGTALK.equals(platform)) {
            String checkedUserId = performanceChartListDTO.getCheckedUserId();
            String checkedDepIdStr = performanceChartListDTO.getCheckedDepId();
            Long checkedDepId;
            Integer companyStructType = performanceChartListDTO.getCompanyStructType();
            CompanyStructTypeEnum companyStructTypeEnum = CompanyStructTypeEnum.getByCode(companyStructType);

            if (companyStructTypeEnum == CompanyStructTypeEnum.UNKNOWN) {
                throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, String.format(PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), "业绩类型"));
            }
            if (CompanyStructTypeEnum.USER == companyStructTypeEnum) {
                if (StringUtil.isEmpty(checkedUserId)) {
                    throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, String.format(PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), "员工"));
                }
            } else if (CompanyStructTypeEnum.DEPARTMENT == companyStructTypeEnum) {
                if (checkedDepIdStr == null || checkedDepIdStr.equals(BasicConstant.ZERO.toString())) {
                    throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, String.format(PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), "部门"));
                }
                try {
                    checkedDepId = Long.parseLong(checkedDepIdStr);
                } catch (NumberFormatException e) {
                    checkedDepId = null;
                }
                if (Objects.isNull(checkedDepId)) {
                    throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, String.format(PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), "部门"));
                }
            } else {
                throw new XbbException(PerformanceErrorCodeEnum.API_ERROR_240006, String.format(PerformanceErrorCodeEnum.API_ERROR_240006.getMsg(), "正确的业绩类型"));
            }
        }
    }

    /**
     * 获取目标管理列表title
     * @param performanceChartListVO
     * @param fromDetail
     * @param statisticsType
     */
    private void getTitleArray(PerformanceChartListVO performanceChartListVO,Integer fromDetail,Integer statisticsType){
        JSONArray titleArray = new JSONArray();
        if (!Objects.equals(fromDetail,BasicConstant.ONE)){
            for (PerformanceTitleEnum item : PerformanceTitleEnum.getAllEnum()) {
                if (Objects.equals(statisticsType, StatisticsTypeEnum.SYSTEM_STATISTIC.getCode()) && Objects.equals(item.getKey(), PerformanceTitleEnum.CREATOR_ID.getKey())) {
                    continue;
                }
                JSONObject jsonObject = new JSONObject();
                jsonObject.put(StringConstant.KEY, item.getKey());
                jsonObject.put(StringConstant.VALUE, item.getName());
                titleArray.add(jsonObject);
            }
            performanceChartListVO.setTitle(titleArray);
        }
    }

    private JSONArray getOperates(PerformanceChartListDTO performanceChartListDTO){
        JSONArray operate = new JSONArray();
        Integer fromDetail = performanceChartListDTO.getFromDetail();
        Integer statisticsType = performanceChartListDTO.getStatisticsType();
        if (!Objects.equals(fromDetail,BasicConstant.ONE)){
            Set<String> saasPermissions = performanceChartListDTO.getLoginUser().getPermSet();
            List<PerformanceOperatorEnum> operatorList = PerformanceOperatorEnum.getByStatisticsType(statisticsType,saasPermissions);
            if (CollectionUtils.isNotEmpty(operatorList)){
                operatorList.forEach(operateItem ->{
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put(StringConstant.ATTR,operateItem.getKey());
                    jsonObject.put(StringConstant.VALUE,operateItem.getName());
                    operate.add(jsonObject);
                });
            }
        }
        return operate;
    }

    /**
     * 获取部门容器
     * @param baseDTO 接口入参实体
     * @param userIds 图表创建人的id数组
     * @return
     * @throws XbbException
     */
    private Map<String, UserEntity> getUserMap(BaseDTO baseDTO,List<String> userIds) throws XbbException {
        // 获取用户部门容器
        Map<String, Object> params = BeanUtil.convertBean2Map(baseDTO, true);
        params.remove("del");
        params.put("userIdIn",userIds);
        params.put(ParameterConstant.LEAVE_MARKS, BasicConstant.ONE);
        List<UserEntity> userList = userModel.findEntitys(params);
        params.remove(ParameterConstant.LEAVE_MARKS);
        if (userList == null) {
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001, MessageConstant.USER_NOT_EXIST);
        }
        Map<String, UserEntity> userMap = new HashMap<>(userList.size());
        userList.forEach((item) -> {
            userMap.put(item.getUserId(), item);
        });
        return userMap;
    }
}
